diff --git a/components/ctx/ctx.h b/components/ctx/ctx.h
index 8d7b68591172a82bedf798617cd5355d4b4e2217..29ea5f40e2a602e4cb9c1e2f89b815e91409b153 100644
--- a/components/ctx/ctx.h
+++ b/components/ctx/ctx.h
@@ -1,4 +1,4 @@
-/* ctx git commit: fe7eaf99 */
+/* ctx git commit: 2db2b527 */
 /* 
  * ctx.h is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -830,8 +830,7 @@ typedef enum CtxFlags {
 
 Ctx *ctx_new_cb (int width, int height, CtxPixelFormat format,
                  void (*set_pixels) (Ctx *ctx, void *user_data, 
-                                     int x, int y, int w, int h, void *buf,
-                                     int buf_size),
+                                     int x, int y, int w, int h, void *buf),
                  void *set_pixels_user_data,
                  int (*update_fb) (Ctx *ctx, void *user_data),
                  void *update_fb_user_data,
@@ -2507,11 +2506,13 @@ uint32_t    ctx_strhash (const char *str);
 void _ctx_write_png (const char *dst_path, int w, int h, int num_chans, void *data);
 
 
+int ctx_vt_available (Ctx *ctx);
 void ctx_vt_write (Ctx *ctx, uint8_t byte);
 int ctx_vt_has_data (Ctx *ctx);
 int ctx_vt_read (Ctx *ctx);
 
 
+int ctx_vt_cursor_y (CtxClient *client);
 
 #if CTX_GSTATE_PROTECT
 /* sets the current gstate stack (number of unpaired ctx_save calls) as a
@@ -2612,7 +2613,7 @@ void        ctx_string_append_float   (CtxString *string, float val);
   jklmnopqrstuvwxyz{|}~  */
 static const struct __attribute__ ((packed)) {uint8_t code; uint32_t a; uint32_t b;}
 ctx_font_ascii[]={
-{15, 0x0000a008, 0x000007a7},/* length:1959 CTX_SUBDIV:8 CTX_BAKE_FONT_SIZE:160 */
+{15, 0x00000000, 0x000007a7},/* length:1959 CTX_SUBDIV:8 CTX_BAKE_FONT_SIZE:160 */
 {'(', 0x00000008, 0x00000001},/* Roboto*/
 {32, 0x6f626f52, 0x00006f74},
 {')', 0x00000008, 0x00000001},
@@ -5770,7 +5771,7 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #endif
 
 #ifndef CTX_STROKE_1PX   
-#define CTX_STROKE_1PX    0
+#define CTX_STROKE_1PX    1
 #endif
 
 #ifndef CTX_PICO
@@ -5790,11 +5791,31 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_COMPOSITE_O2 0
 #endif
 
+#ifndef CTX_RASTERIZER_O3
+#define CTX_RASTERIZER_O3 0
+#endif
+
+#ifndef CTX_RASTERIZER_O2
+#define CTX_RASTERIZER_O2 0
+#endif
+
 #if CTX_KMS || CTX_FB
 #undef CTX_RAW_KB_EVENTS
 #define CTX_RAW_KB_EVENTS 1
 #endif
 
+#ifndef CTX_YUV_LUTS
+#define  CTX_YUV_LUTS 0
+#endif
+
+
+#ifndef CTX_CB_ENABLE_LOW_FI
+#define CTX_CB_ENABLE_LOW_FI 1
+#endif
+
+#ifndef CTX_VT_STYLE_SIZE
+#define CTX_VT_STYLE_SIZE 32
+#endif
  /* Copyright (C) 2020 Øyvind Kolås <pippin@gimp.org>
  */
 
@@ -10117,6 +10138,8 @@ struct _CtxClient {
 };
 
 
+void ctx_client_lock (CtxClient *client);
+void ctx_client_unlock (CtxClient *client);
 
 #endif
 
@@ -10717,6 +10740,10 @@ struct _CtxInternalFsEntry
   char *data;
 };
 
+
+typedef void (*ctx_apply_coverage_fun) (CtxRasterizer *r, uint8_t * __restrict__ dst, uint8_t * __restrict__ src, int x, uint8_t *coverage,
+                          unsigned int count);
+
 struct _CtxPixelFormatInfo
 {
   CtxPixelFormat pixel_format:8;
@@ -10735,8 +10762,7 @@ struct _CtxPixelFormatInfo
                            int x, const void * __restrict__ src, uint8_t * __restrict__ comp, int count);
   void         (*from_comp) (CtxRasterizer *r,
                              int x, const uint8_t * __restrict__ comp, void *__restrict__ dst, int count);
-  void         (*apply_coverage) (CtxRasterizer *r, uint8_t * __restrict__ dst, uint8_t * __restrict__ src, int x, uint8_t *coverage,
-                          unsigned int count);
+  ctx_apply_coverage_fun apply_coverage;
   void         (*setup) (CtxRasterizer *r);
 };
 
@@ -10836,9 +10862,9 @@ struct _CtxRasterizer
   unsigned int aa;          // level of vertical aa
   unsigned int active_edges;
   unsigned int pending_edges;
+  unsigned int horizontal_edges;
   unsigned int ending_edges;
   unsigned int edge_pos;         // where we're at in iterating all edges
-  unsigned int horizontal_edges;
 
   int        scanline;
   int        scan_min;
@@ -13540,14 +13566,82 @@ ctx_fragment_image_rgba8_RGBA8_bi (CtxRasterizer *rasterizer,
   val *= val > 0;\
   val = (val > 255) * 255 + (val <= 255) * val
 
+#if CTX_YUV_LUTS
+static const int16_t ctx_y_to_cy[256]={
+-19,-18,-17,-16,-14,-13,-12,-11,-10,-9,-7,-6,-5,-4,-3,
+-2,0,1,2,3,4,5,6,8,9,10,11,12,13,15,
+16,17,18,19,20,22,23,24,25,26,27,29,30,31,32,
+33,34,36,37,38,39,40,41,43,44,45,46,47,48,50,
+51,52,53,54,55,57,58,59,60,61,62,64,65,66,67,
+68,69,71,72,73,74,75,76,78,79,80,81,82,83,84,
+86,87,88,89,90,91,93,94,95,96,97,98,100,101,102,
+103,104,105,107,108,109,110,111,112,114,115,116,117,118,119,
+121,122,123,124,125,126,128,129,130,131,132,133,135,136,137,
+138,139,140,142,143,144,145,146,147,149,150,151,152,153,154,
+156,157,158,159,160,161,163,164,165,166,167,168,169,171,172,
+173,174,175,176,178,179,180,181,182,183,185,186,187,188,189,
+190,192,193,194,195,196,197,199,200,201,202,203,204,206,207,
+208,209,210,211,213,214,215,216,217,218,220,221,222,223,224,
+225,227,228,229,230,231,232,234,235,236,237,238,239,241,242,
+243,244,245,246,248,249,250,251,252,253,254,256,257,258,259,
+260,261,263,264,265,266,267,268,270,271,272,273,274,275,277,
+278};
+static const int16_t ctx_u_to_cb[256]={
+-259,-257,-255,-253,-251,-249,-247,-245,-243,-241,-239,-237,-234,-232,-230,
+-228,-226,-224,-222,-220,-218,-216,-214,-212,-210,-208,-206,-204,-202,-200,
+-198,-196,-194,-192,-190,-188,-186,-184,-182,-180,-178,-176,-174,-172,-170,
+-168,-166,-164,-162,-160,-158,-156,-154,-152,-150,-148,-146,-144,-142,-140,
+-138,-136,-134,-132,-130,-128,-126,-124,-122,-120,-117,-115,-113,-111,-109,
+-107,-105,-103,-101,-99,-97,-95,-93,-91,-89,-87,-85,-83,-81,-79,
+-77,-75,-73,-71,-69,-67,-65,-63,-61,-59,-57,-55,-53,-51,-49,
+-47,-45,-43,-41,-39,-37,-35,-33,-31,-29,-27,-25,-23,-21,-19,
+-17,-15,-13,-11,-9,-7,-5,-3,0,2,4,6,8,10,12,
+14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,
+44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,
+74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,
+104,106,108,110,112,114,116,119,121,123,125,127,129,131,133,
+135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,
+165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,
+195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,
+225,227,229,231,233,236,238,240,242,244,246,248,250,252,254,
+256};
+static const int16_t ctx_v_to_cr[256]={
+-205,-203,-202,-200,-198,-197,-195,-194,-192,-190,-189,-187,-186,-184,-182,
+-181,-179,-178,-176,-174,-173,-171,-170,-168,-166,-165,-163,-162,-160,-159,
+-157,-155,-154,-152,-151,-149,-147,-146,-144,-143,-141,-139,-138,-136,-135,
+-133,-131,-130,-128,-127,-125,-123,-122,-120,-119,-117,-115,-114,-112,-111,
+-109,-107,-106,-104,-103,-101,-99,-98,-96,-95,-93,-91,-90,-88,-87,
+-85,-83,-82,-80,-79,-77,-76,-74,-72,-71,-69,-68,-66,-64,-63,
+-61,-60,-58,-56,-55,-53,-52,-50,-48,-47,-45,-44,-42,-40,-39,
+-37,-36,-34,-32,-31,-29,-28,-26,-24,-23,-21,-20,-18,-16,-15,
+-13,-12,-10,-8,-7,-5,-4,-2,0,1,3,4,6,7,9,
+11,12,14,15,17,19,20,22,23,25,27,28,30,31,33,
+35,36,38,39,41,43,44,46,47,49,51,52,54,55,57,
+59,60,62,63,65,67,68,70,71,73,75,76,78,79,81,
+82,84,86,87,89,90,92,94,95,97,98,100,102,103,105,
+106,108,110,111,113,114,116,118,119,121,122,124,126,127,129,
+130,132,134,135,137,138,140,142,143,145,146,148,150,151,153,
+154,156,158,159,161,162,164,165,167,169,170,172,173,175,177,
+178,180,181,183,185,186,188,189,191,193,194,196,197,199,201,
+202};
+
+#endif
+
 static inline uint32_t ctx_yuv_to_rgba32 (uint8_t y, uint8_t u, uint8_t v)
 {
+#if CTX_YUV_LUTS
+  int cy  = ctx_y_to_cy[y];
+  int red = cy + ctx_v_to_cr[v];
+  int green = cy - (((u-128) * 25674 + (v-128) * 53278) >> 16);
+  int blue = cy + ctx_u_to_cb[u];
+#else
   int cy  = ((y - 16) * 76309) >> 16;
   int cr  = (v - 128);
   int cb  = (u - 128);
   int red = cy + ((cr * 104597) >> 16);
   int green = cy - ((cb * 25674 + cr * 53278) >> 16);
   int blue = cy + ((cb * 132201) >> 16);
+#endif
   ctx_clamp_byte (red);
   ctx_clamp_byte (green);
   ctx_clamp_byte (blue);
@@ -15343,7 +15437,7 @@ ctx_setup_RGB8 (CtxRasterizer *rasterizer)
 }
 #endif
 
-static void
+static inline void
 ctx_composite_convert (CTX_COMPOSITE_ARGUMENTS)
 {
   uint8_t pixels[count * rasterizer->format->ebpp];
@@ -17720,13 +17814,12 @@ ctx_RGBA8_source_copy_normal_color (CTX_COMPOSITE_ARGUMENTS);
 static void
 ctx_composite_RGB565 (CTX_COMPOSITE_ARGUMENTS)
 {
-#if 1
-  if (CTX_LIKELY(rasterizer->comp_op == ctx_RGBA8_source_over_normal_color))
+#if 0 // code is OK - but less code is better
+  if (rasterizer->comp_op == ctx_RGBA8_source_over_normal_color)
   {
     uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
     uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
     uint32_t si_a  = si_ga >> 16;
-
     while (count--)
     {
         uint32_t cov   = *coverage++;
@@ -17741,6 +17834,25 @@ ctx_composite_RGB565 (CTX_COMPOSITE_ARGUMENTS)
     }
     return;
   }
+  if (rasterizer->comp_op == ctx_RGBA8_source_copy_normal_color)
+  {
+    uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
+    uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
+    uint32_t si_a  = si_ga >> 16;
+    while (count--)
+    {
+        uint32_t cov   = *coverage++;
+        uint32_t rcov  = cov^255;
+        uint32_t di    = ctx_565_to_888 (*((uint16_t*)dst), 0);
+        uint32_t di_ga = ((di & 0xff00ff00) >> 8);
+        uint32_t di_rb = (di & 0x00ff00ff);
+        *((uint16_t*)(dst)) =
+        ctx_888_to_565((((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
+         ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00), 0);
+         dst+=2;
+    }
+    return;
+  }
 #endif
 
   uint8_t pixels[count * 4];
@@ -17790,13 +17902,13 @@ ctx_RGBA8_to_RGB565_BS (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, v
 static void
 ctx_composite_RGB565_BS (CTX_COMPOSITE_ARGUMENTS)
 {
-#if 1
-  if (CTX_LIKELY(rasterizer->comp_op == ctx_RGBA8_source_over_normal_color))
+#if 0 // code is OK - but not faster - at least no on risc-V
+  if ((rasterizer->comp_op == ctx_RGBA8_source_over_normal_color)
+      ||(rasterizer->comp_op == ctx_RGBA8_source_copy_normal_color))
   {
     uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
     uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
     uint32_t si_a  = si_ga >> 16;
-
     while (count--)
     {
       uint32_t cov   = *coverage++;
@@ -17812,6 +17924,26 @@ ctx_composite_RGB565_BS (CTX_COMPOSITE_ARGUMENTS)
     return;
   }
 #endif
+#if 1
+  if (rasterizer->comp_op == ctx_RGBA8_source_copy_normal_color)
+  {
+    uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
+    uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
+    while (count--)
+    {
+        uint8_t cov   = *coverage++;
+        uint8_t rcov  = cov^255;
+        uint32_t di    = ctx_565_to_888 (*((uint16_t*)dst), 1);
+        uint32_t di_ga = ((di & 0xff00ff00) >> 8);
+        uint32_t di_rb = (di & 0x00ff00ff);
+        *((uint16_t*)(dst)) =
+        ctx_888_to_565((((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
+         ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00), 1);
+         dst+=2;
+    }
+    return;
+  }
+#endif
 
   uint8_t pixels[count * 4];
   ctx_RGB565_BS_to_RGBA8 (rasterizer, x0, dst, &pixels[0], count);
@@ -19061,20 +19193,32 @@ CtxPixelFormatInfo CTX_SIMD_SUFFIX(ctx_pixel_formats)[]=
 
 #endif // CTX_IMPLEMENTATION
 
+#ifndef __clang__
+#if CTX_RASTERIZER_O3
+#pragma GCC push_options
+#pragma GCC optimize("O3")
+#endif
+#if CTX_RASTERIZER_O2
+#pragma GCC push_options
+#pragma GCC optimize("O2")
+#endif
+#endif
+
 #if CTX_IMPLEMENTATION || CTX_SIMD_BUILD
 #if CTX_COMPOSITE 
 
 #define CTX_AA_HALFSTEP2   (CTX_FULL_AA/2)
 #define CTX_AA_HALFSTEP    ((CTX_FULL_AA/2)+1)
 
-CTX_INLINE static int ctx_compare_edges (const void *ap, const void *bp)
+
+static inline int ctx_compare_edges (const void *ap, const void *bp)
 {
   const CtxSegment *a = (const CtxSegment *) ap;
   const CtxSegment *b = (const CtxSegment *) bp;
   return a->data.s16[1] - b->data.s16[1];
 }
 
-CTX_INLINE static int ctx_edge_qsort_partition (CtxSegment *A, int low, int high)
+static inline int ctx_edge_qsort_partition (CtxSegment *A, int low, int high)
 {
   CtxSegment pivot = A[ (high+low) /2];
   int i = low;
@@ -19095,6 +19239,14 @@ CTX_INLINE static int ctx_edge_qsort_partition (CtxSegment *A, int low, int high
   return i;
 }
 
+static inline void ctx_edge_qsort (CtxSegment *entries, int low, int high)
+{
+  int p = ctx_edge_qsort_partition (entries, low, high);
+  if (low < p -1 )
+    { ctx_edge_qsort (entries, low, p - 1); }
+  if (low < high)
+    { ctx_edge_qsort (entries, p, high); }
+}
 
 static inline void ctx_rasterizer_discard_edges (CtxRasterizer *rasterizer)
 {
@@ -19102,28 +19254,29 @@ static inline void ctx_rasterizer_discard_edges (CtxRasterizer *rasterizer)
   int next_scanline = scanline + CTX_FULL_AA;
   CtxSegment *segments = &((CtxSegment*)(rasterizer->edge_list.entries))[0];
   int *edges = rasterizer->edges;
-  for (unsigned int i = 0; i < rasterizer->active_edges; i++)
+  int ending_edges = 0;
+  unsigned int active_edges = rasterizer->active_edges;
+  for (unsigned int i = 0; i < active_edges; i++)
     {
       CtxSegment *segment = segments + edges[i];
       int edge_end = segment->data.s16[3];
       if (edge_end < scanline)
         {
-          rasterizer->edges[i] = rasterizer->edges[rasterizer->active_edges-1];
-          rasterizer->active_edges--;
+          rasterizer->edges[i] = rasterizer->edges[active_edges-1];
+          active_edges--;
           i--;
         }
-      else if (edge_end < next_scanline)
-        rasterizer->ending_edges++;
+      else ending_edges += (edge_end < next_scanline);
     }
-#if 0
-  // perhaps we should - but for 99% of the cases we do not need to, so we skip it
-  for (int i = 0; i < rasterizer->pending_edges; i++)
+  rasterizer->active_edges = active_edges;
+
+  unsigned int pending_edges = rasterizer->pending_edges;
+  for (unsigned int i = 0; i < pending_edges; i++)
     {
-      int edge_end = ((CtxSegment*)(rasterizer->edge_list.entries))[rasterizer->edges[CTX_MAX_EDGES-1-i]].data.s16[3]-1;
-      if (edge_end < scanline + CTX_FULL_AA)
-        rasterizer->ending_edges++;
+      int edge_end = ((CtxSegment*)(rasterizer->edge_list.entries))[rasterizer->edges[CTX_MAX_EDGES-1-i]].data.s16[3];
+      ending_edges += (edge_end < next_scanline);
     }
-#endif
+  rasterizer->ending_edges = ending_edges;
 }
 
 inline static void ctx_rasterizer_increment_edges (CtxRasterizer *rasterizer, int count)
@@ -19168,69 +19321,146 @@ inline static void ctx_edge2_insertion_sort (CtxSegment *segments, int *entries,
    }
 }
 
-inline static int ctx_edge2_compare2 (CtxSegment *segments, int a, int b)
-{
-  CtxSegment *seg_a = &segments[a];
-  CtxSegment *seg_b = &segments[b];
-  int minval_a = ctx_mini (seg_a->val - seg_a->delta * CTX_AA_HALFSTEP2, seg_a->val + seg_a->delta * CTX_AA_HALFSTEP);
-  int minval_b = ctx_mini (seg_b->val - seg_b->delta * CTX_AA_HALFSTEP2, seg_b->val + seg_b->delta * CTX_AA_HALFSTEP);
-  return minval_a - minval_b;
-}
-
-inline static void ctx_edge2_insertion_sort2 (CtxSegment *segments, int *entries, unsigned int count)
-{
-  for(unsigned int i=1; i<count; i++)
-   {
-     int temp = entries[i];
-     int j = i-1;
-     while (j >= 0 && ctx_edge2_compare2 (segments, temp, entries[j]) < 0)
-     {
-       entries[j+1] = entries[j];
-       j--;
-     }
-     entries[j+1] = temp;
-   }
-}
-
 inline static void ctx_rasterizer_feed_edges (CtxRasterizer *rasterizer)
 {
-  int miny;
   CtxSegment *__restrict__ entries = (CtxSegment*)&rasterizer->edge_list.entries[0];
   int *edges = rasterizer->edges;
   unsigned int pending_edges   = rasterizer->pending_edges;
-  rasterizer->horizontal_edges = 0;
-  rasterizer->ending_edges     = 0;
   int scanline = rasterizer->scanline + 1;
+  int active_edges = rasterizer->active_edges;
   for (unsigned int i = 0; i < pending_edges; i++)
     {
       if (entries[rasterizer->edges[CTX_MAX_EDGES-1-i]].data.s16[1] <= scanline &&
-          rasterizer->active_edges < CTX_MAX_EDGES-2)
+          active_edges < CTX_MAX_EDGES-2)
         {
-          unsigned int no = rasterizer->active_edges;
-          rasterizer->active_edges++;
-          edges[no] = edges[CTX_MAX_EDGES-1-i];
+          edges[active_edges] = edges[CTX_MAX_EDGES-1-i];
+          active_edges++;
           edges[CTX_MAX_EDGES-1-i] =
             edges[CTX_MAX_EDGES-1-pending_edges + 1];
           pending_edges--;
           i--;
         }
     }
-  int next_scanline = scanline + CTX_FULL_AA;
+    rasterizer->active_edges = active_edges;
+    rasterizer->pending_edges = pending_edges;
+    ctx_rasterizer_discard_edges (rasterizer);
+}
+
+inline static int analyze_scanline (CtxRasterizer *rasterizer)
+{
+  if (rasterizer->active_edges + rasterizer->pending_edges == 0)
+    return -1;
+  if ((rasterizer->fast_aa == 0) |
+      rasterizer->horizontal_edges|
+      rasterizer->ending_edges|
+      rasterizer->pending_edges)
+  {
+    return CTX_RASTERIZER_AA;
+  }
+
+  const int *edges  = rasterizer->edges;
+  const CtxSegment *segments = &((CtxSegment*)(rasterizer->edge_list.entries))[0];
+
+  int active_edges = rasterizer->active_edges;
+
+  int crossings = 0;
+#if CTX_RASTERIZER_AA>5
+  int needs_aa15 =0;
+#endif
+#if CTX_RASTERIZER_AA>3
+  int needs_aa5 =0;
+#endif
+  int needs_aa3 =0;
+
+  const CtxSegment *segment0 = segments + edges[0];
+  const int delta0    = segment0->delta;
+  const int x0        = segment0->val;
+  int x0_end   = x0 + delta0 * CTX_AA_HALFSTEP;
+  int x0_start = x0 - delta0 * CTX_AA_HALFSTEP2;
+
+#if CTX_RASTERIZER_AA>5
+  needs_aa15 += (abs(delta0) > CTX_RASTERIZER_AA_SLOPE_LIMIT15);
+#endif
+#if CTX_RASTERIZER_AA>3
+  needs_aa5 += (abs(delta0) > CTX_RASTERIZER_AA_SLOPE_LIMIT5);
+#endif
+  needs_aa3 += (abs(delta0) > CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA);
+
+  for (int t = 0; t < active_edges -1;t++)
+    {
+      const CtxSegment *segment1 = segments + edges[t+1];
+      const int delta1    = segment1->delta;
+      const int x1        = segment1->val;
+
+#if CTX_RASTERIZER_AA>5
+      needs_aa15 += (abs(delta1) > CTX_RASTERIZER_AA_SLOPE_LIMIT15);
+#endif
+#if CTX_RASTERIZER_AA>3
+      needs_aa5 += (abs(delta1) > CTX_RASTERIZER_AA_SLOPE_LIMIT5);
+#endif
+      needs_aa3 += (abs(delta1) > CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA);
+
+      const int x1_end   = x1 + delta1 * CTX_AA_HALFSTEP;
+      const int x1_start = x1 - delta1 * CTX_AA_HALFSTEP2;
+      if (x1_end < x0_end   ||
+          x1_start < x0_end ||
+          x1_end < x0_start
+         )
+      {
+         crossings++;
+#if CTX_RASTERIZER_AA==3
+         if (needs_aa3)
+            break;
+#elif CTX_RASTERIZER_AA==5
+         if (needs_aa5)
+            break;
+#elif CTX_RASTERIZER_AA==15
+         if (needs_aa15)
+            break;
+#endif
+      }
+      x0_end = x1_end;
+      x0_start = x1_start;
+    }
+
+  if (crossings)
+  {
+#if CTX_RASTERIZER_AA>5
+    if (needs_aa15) return 15;
+#endif
+#if CTX_RASTERIZER_AA>3
+    if (needs_aa5) return 5;
+#endif
+    if (needs_aa3) return 3;
+    return 1;
+  }
+  return 0;
+}
+
+inline static int ctx_rasterizer_feed_edges_full (CtxRasterizer *rasterizer)
+{
+  int miny;
+  ctx_rasterizer_feed_edges (rasterizer);
+  CtxSegment *__restrict__ entries = (CtxSegment*)&rasterizer->edge_list.entries[0];
+  int *edges = rasterizer->edges;
+  unsigned int pending_edges   = rasterizer->pending_edges;
+  int scanline = rasterizer->scanline + 1;
   unsigned int edge_pos = rasterizer->edge_pos;
+  int next_scanline = scanline + CTX_FULL_AA;
   unsigned int edge_count = rasterizer->edge_list.count;
+  int active_edges = rasterizer->active_edges;
+  rasterizer->horizontal_edges = 0;
   while ((edge_pos < edge_count &&
          (miny=entries[edge_pos].data.s16[1])  <= next_scanline))
     {
-      if (rasterizer->active_edges < CTX_MAX_EDGES-2 &&
+      if (active_edges < CTX_MAX_EDGES-2 &&
       entries[edge_pos].data.s16[3] /* (maxy) */  >= scanline)
         {
           int dy = (entries[edge_pos].data.s16[3] - miny);
           if (dy)
             {
               int yd = scanline - miny;
-              unsigned int no = rasterizer->active_edges;
-              rasterizer->active_edges++;
-              unsigned int index = edges[no] = edge_pos;
+              unsigned int index = edges[active_edges] = edge_pos;
               int x0 = entries[index].data.s16[0];
               int x1 = entries[index].data.s16[2];
               int dx_dy = CTX_RASTERIZER_EDGE_MULTIPLIER * (x1 - x0) / dy;
@@ -19246,21 +19476,22 @@ inline static void ctx_rasterizer_feed_edges (CtxRasterizer *rasterizer)
                      a heap and stack growing against each other
                   */
                     edges[CTX_MAX_EDGES-1-pending_edges] =
-                    rasterizer->edges[no];
+                    rasterizer->edges[active_edges];
                     pending_edges++;
-                    rasterizer->active_edges--;
+                    active_edges--;
               }
+              active_edges++;
             }
-          else
-            rasterizer->horizontal_edges ++;
+            else
+            rasterizer->horizontal_edges++;
         }
       edge_pos++;
     }
-    rasterizer->pending_edges = pending_edges;
+    rasterizer->active_edges = active_edges;
     rasterizer->edge_pos = edge_pos;
-    ctx_rasterizer_discard_edges (rasterizer);
+    rasterizer->pending_edges = pending_edges;
+    return analyze_scanline (rasterizer);
 }
-#undef CTX_CMPSWP
 
 static inline void ctx_coverage_post_process (CtxRasterizer *rasterizer, unsigned int minx, unsigned int maxx, uint8_t *coverage, int *first_col, int *last_col)
 {
@@ -19436,12 +19667,10 @@ ctx_rasterizer_generate_coverage_apply (CtxRasterizer *rasterizer,
                                         int            maxx,
                //                       uint8_t* __restrict__ coverage,
                                         int            is_winding,
-                                        CtxCovPath     comp)
+                                        CtxCovPath     comp,
+                                        ctx_apply_coverage_fun apply_coverage)
 {
   CtxSegment *entries = (CtxSegment*)(&rasterizer->edge_list.entries[0]);
-  void (*apply_coverage)(CtxRasterizer *r, uint8_t *dst, uint8_t *src,
-                         int x, uint8_t *coverage, unsigned int count) =
-      rasterizer->apply_coverage;
   uint8_t *rasterizer_src = rasterizer->color;
   int *edges          = rasterizer->edges;
   int scanline        = rasterizer->scanline;
@@ -19983,16 +20212,14 @@ ctx_rasterizer_generate_coverage_apply2 (CtxRasterizer *rasterizer,
                                          int            maxx,
                                          uint8_t       *coverage,
                                          int            is_winding,
-                                         CtxCovPath     comp)
+                                         CtxCovPath     comp,
+                                         ctx_apply_coverage_fun apply_coverage)
 {
   CtxSegment *entries = (CtxSegment*)(&rasterizer->edge_list.entries[0]);
   int *edges          = rasterizer->edges;
   int  scanline       = rasterizer->scanline;
   const int  bpp      = rasterizer->format->bpp;
   int  active_edges   = rasterizer->active_edges;
-  void (*apply_coverage)(CtxRasterizer *r, uint8_t *dst, uint8_t *src,
-                         int x, uint8_t *coverage, unsigned int count) =
-      rasterizer->apply_coverage;
   uint8_t *rasterizer_src = rasterizer->color;
   int  parity         = 0;
 
@@ -20099,7 +20326,7 @@ ctx_rasterizer_generate_coverage_apply2 (CtxRasterizer *rasterizer,
               coverage[us + count] += ((u - u0 + mod) * recip)>>16;
               count++;
             }
-            pre = (us+count-1)-first+1;
+            pre = us+count-first;
 
             accumulated_x0 = ctx_mini (accumulated_x0, us);
             accumulated_x1 = us + count - 1;
@@ -20395,7 +20622,6 @@ ctx_rasterizer_generate_coverage_apply2 (CtxRasterizer *rasterizer,
    }
 }
 
-#undef CTX_EDGE_Y0
 #undef CTX_EDGE
 
 static inline void
@@ -20418,90 +20644,7 @@ ctx_rasterizer_reset (CtxRasterizer *rasterizer)
   //     nonchanging
 }
 
-inline static int analyze_scanline (CtxRasterizer *rasterizer)
-{
-  if (rasterizer->fast_aa == 0 ||
-      rasterizer->ending_edges ||
-      rasterizer->pending_edges)
-   return CTX_RASTERIZER_AA;
-
-  int *edges  = rasterizer->edges;
-  CtxSegment *segments = &((CtxSegment*)(rasterizer->edge_list.entries))[0];
-
-  int active_edges = rasterizer->active_edges;
 
-  int crossings = 0;
-#if CTX_RASTERIZER_AA>5
-  int needs_aa15 =0;
-#endif
-#if CTX_RASTERIZER_AA>3
-  int needs_aa5 =0;
-#endif
-  int needs_aa3 =0;
-
-  // XX : include pending?
-  for (int t = 0; t < active_edges -1;t++)
-    {
-      CtxSegment *segment0 = segments + edges[t];
-      CtxSegment *segment1 = segments + edges[t+1];
-      const int delta0    = segment0->delta;
-      const int delta1    = segment1->delta;
-      const int x0        = segment0->val;
-      const int x1        = segment1->val;
-
-#if CTX_RASTERIZER_AA>5
-      needs_aa15 += (abs(delta0) > CTX_RASTERIZER_AA_SLOPE_LIMIT15);
-      if (crossings)
-        break;
-#endif
-#if CTX_RASTERIZER_AA>3
-      needs_aa5 += (abs(delta0) > CTX_RASTERIZER_AA_SLOPE_LIMIT5);
-#endif
-      needs_aa3 += (abs(delta0) > CTX_RASTERIZER_AA_SLOPE_LIMIT3);
-      int x0_end   = x0 + delta0 * CTX_AA_HALFSTEP;
-      int x1_end   = x1 + delta1 * CTX_AA_HALFSTEP;
-      int x0_start = x0 - delta0 * CTX_AA_HALFSTEP2;
-      int x1_start = x1 - delta1 * CTX_AA_HALFSTEP2;
-      if (x1_end < x0_end   ||
-          x1_start < x0_end ||
-          x1_end < x0_start
-         )
-      {
-         crossings++;
-#if CTX_RASTERIZER_AA==3
-         if (needs_aa3)
-            break;
-#elif CTX_RASTERIZER_AA==5
-         if (needs_aa5)
-            break;
-#elif CTX_RASTERIZER_AA==15
-         if (needs_aa15)
-            break;
-#endif
-      }
-    }
-  if (crossings)
-  {
-#if CTX_RASTERIZER_AA>5
-    if (needs_aa15) return 15;
-#endif
-#if CTX_RASTERIZER_AA>3
-    if (needs_aa5) return 5;
-#endif
-    if (needs_aa3) return 3;
-    return 1;
-  }
-  return 0;
-}
-
-static inline void ctx_edge_qsort (CtxSegment *entries, int low, int high)
-{
-  int p = ctx_edge_qsort_partition (entries, low, high);
-  if (low < p -1 )
-    { ctx_edge_qsort (entries, low, p - 1); }
-  if (low < high)
-    { ctx_edge_qsort (entries, p, high); }
-}
 
 static void
 ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
@@ -20520,10 +20663,8 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
   int       maxx        = (rasterizer->col_max + CTX_SUBDIV-1) / CTX_SUBDIV -
                           rasterizer->blit_x;
   const int blit_stride = rasterizer->blit_stride;
-  //int       increment   = CTX_FULL_AA/real_aa;
-  void (*apply_coverage)(CtxRasterizer *r, uint8_t *dst, uint8_t *src,
-                         int x, uint8_t *coverage, unsigned int count) =
-      rasterizer->apply_coverage;
+
+  ctx_apply_coverage_fun apply_coverage = rasterizer->apply_coverage;
   uint8_t *rasterizer_src = rasterizer->color;
 
   if (maxx > blit_max_x - 1)
@@ -20534,10 +20675,6 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
   minx *= (minx>0);
  
 
-  if (CTX_UNLIKELY (minx >= maxx))
-    {
-      return;
-    }
   int pixs = maxx - minx + 1;
   uint8_t _coverage[pixs];
   uint8_t *coverage = &_coverage[0];
@@ -20558,7 +20695,7 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
        scan_start = rasterizer->state->gstate.clip_min_y * CTX_FULL_AA; 
     }
   scan_end = ctx_mini (rasterizer->state->gstate.clip_max_y * CTX_FULL_AA, scan_end);
-  if (CTX_UNLIKELY(scan_start > scan_end ||
+  if (CTX_UNLIKELY((minx >= maxx) || (scan_start > scan_end) ||
       (scan_start > (rasterizer->blit_y + (rasterizer->blit_height-1)) * CTX_FULL_AA) ||
       (scan_end < (rasterizer->blit_y) * CTX_FULL_AA)))
   { 
@@ -20566,42 +20703,37 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
     return;
   }
 
-  rasterizer->horizontal_edges = 0;
-
   ctx_edge_qsort ((CtxSegment*)& (rasterizer->edge_list.entries[0]), 0, rasterizer->edge_list.count-1);
   rasterizer->scanline = scan_start;
 
-  int avoid_direct = (0 
+  int allow_direct = !(0 
 #if CTX_ENABLE_CLIP
-         || rasterizer->clip_buffer
+         || (rasterizer->clip_buffer && (!rasterizer->clip_rectangle))
 #endif
 #if CTX_ENABLE_SHADOW_BLUR
          || rasterizer->in_shadow
 #endif
          );
-
   for (; rasterizer->scanline <= scan_end;)
     {
-      ctx_rasterizer_feed_edges (rasterizer);
+      int aa = ctx_rasterizer_feed_edges_full (rasterizer);
 
-      if (rasterizer->active_edges + rasterizer->pending_edges == 0)
-      { /* no edges */
-        ctx_rasterizer_increment_edges (rasterizer, CTX_FULL_AA);
+      switch (aa)
+      {
+        case -1:
+        rasterizer->scanline += CTX_FULL_AA;
         dst += blit_stride;
         continue;
-      } else
-      {
-        int aa = analyze_scanline (rasterizer);
-        if (aa==0)
+        case 0:
         { /* the scanline transitions does not contain multiple intersections - each aa segment is a linear ramp */
           ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP2);
-          //ctx_rasterizer_feed_edges (rasterizer);
-          ctx_edge2_insertion_sort2 ((CtxSegment*)rasterizer->edge_list.entries, rasterizer->edges, rasterizer->active_edges);
+          ctx_rasterizer_feed_edges (rasterizer);
+          ctx_edge2_insertion_sort ((CtxSegment*)rasterizer->edge_list.entries, rasterizer->edges, rasterizer->active_edges);
     
           memset (coverage, 0, pixs);
-          if (!avoid_direct)
+          if (allow_direct)
           {
-            ctx_rasterizer_generate_coverage_apply2 (rasterizer, minx, maxx, coverage, is_winding, comp);
+            ctx_rasterizer_generate_coverage_apply2 (rasterizer, minx, maxx, coverage, is_winding, comp, apply_coverage);
             ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
     
             dst += blit_stride;
@@ -20609,22 +20741,18 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
           }
           ctx_rasterizer_generate_coverage_set2 (rasterizer, minx, maxx, coverage, is_winding);
           ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
-          if (real_aa == 1)
-          {
-            for (int x = minx; x <= maxx; x ++)
-              coverage[x] = coverage[x] > 127?255:0;
-          }
+          break;
         }
-        else if (aa == 1) // marginal improvement on esp32
+        case 1:
         {
           ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP2);
           ctx_rasterizer_feed_edges (rasterizer);
           ctx_edge2_insertion_sort ((CtxSegment*)rasterizer->edge_list.entries, rasterizer->edges, rasterizer->active_edges);
     
-          if (! avoid_direct)
+          if (allow_direct)
           { /* can generate with direct rendering to target (we're not using shape cache) */
     
-            ctx_rasterizer_generate_coverage_apply (rasterizer, minx, maxx, is_winding, comp);
+            ctx_rasterizer_generate_coverage_apply (rasterizer, minx, maxx, is_winding, comp, apply_coverage);
             ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
     
             dst += blit_stride;
@@ -20637,25 +20765,25 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
             ctx_rasterizer_generate_coverage_set (rasterizer, minx, maxx, coverage, is_winding);
             ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
           }
+          break;
         }
-        else
-        { /* determine level of oversampling based on lowest steepness edges */
+        default:
+        { /* level of oversampling based on lowest steepness edges */
           if (aa > real_aa) aa = real_aa;
           int scanline_increment = 15/aa;
-    
           memset (coverage, 0, pixs);
           uint8_t fraction = 255/aa;
           for (int i = 0; i < CTX_FULL_AA; i+= scanline_increment)
           {
+            if (i) ctx_rasterizer_feed_edges (rasterizer);
             ctx_edge2_insertion_sort ((CtxSegment*)rasterizer->edge_list.entries, rasterizer->edges, rasterizer->active_edges);
             ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, is_winding, aa, fraction);
             ctx_rasterizer_increment_edges (rasterizer, scanline_increment);
-            ctx_rasterizer_feed_edges (rasterizer);
           }
         }
       }
   
-    ctx_coverage_post_process (rasterizer, minx, maxx, coverage - minx, NULL, NULL);
+      ctx_coverage_post_process (rasterizer, minx, maxx, coverage - minx, NULL, NULL);
       apply_coverage (rasterizer,
                       &dst[(minx * rasterizer->format->bpp) /8],
                       rasterizer_src,
@@ -20665,6 +20793,7 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
       dst += blit_stride;
     }
 
+#if CTX_BLENDING_AND_COMPOSITING
   if (CTX_UNLIKELY(rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_OUT ||
       rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_IN ||
       rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_DESTINATION_IN ||
@@ -20733,6 +20862,7 @@ ctx_rasterizer_rasterize_edges2 (CtxRasterizer *rasterizer, const int fill_rule)
      }
 #endif
   }
+#endif
 }
 
 
@@ -21644,9 +21774,9 @@ ctx_rasterizer_stroke_1px_segment (CtxRasterizer *rasterizer,
   int pitch = rasterizer->format->bpp / 8;
   int blit_stride = rasterizer->blit_stride;
 
-  x1 += 0.5f;
+  //x1 += 0.5f;
   y1 += 0.5f;
-  x0 += 0.5f;
+  //x0 += 0.5f;
   y0 += 0.5f;
 
   float dxf = (x1 - x0);
@@ -21826,14 +21956,9 @@ ctx_rasterizer_stroke (CtxRasterizer *rasterizer)
   ctx_composite_setup (rasterizer);
 
 #if CTX_STROKE_1PX
-  if ((gstate->line_width * factor <= 0.0f &&
-       gstate->line_width * factor > -10.0f)
-
-     ||(    gstate->line_width * factor >= 0.99f 
-         && gstate->line_width * factor <= 1.01f 
-         && gstate->n_dashes  == 0
-        )
-     )
+  if (gstate->line_width * factor <= 0.0f &&
+      gstate->line_width * factor > -10.0f &&
+      rasterizer->format->bpp >= 8)
   {
     ctx_rasterizer_stroke_1px (rasterizer);
     if (preserved)
@@ -23516,6 +23641,14 @@ ctx_state_gradient_clear_stops (CtxState *state)
 }
 
 
+#ifndef __clang__
+#if CTX_RASTERIZER_O3
+#pragma GCC pop_options
+#endif
+#if CTX_RASTERIZER_O2
+#pragma GCC pop_options
+#endif
+#endif
 /****  end of engine ****/
 //#include "miniz.h"
 /**************************************************************************
@@ -37115,7 +37248,7 @@ ctx_wasm_get_context (int flags);
 
 static Ctx *ctx_new_ui (int width, int height, const char *backend)
 {
-   return ctx_wasm_get_context (CTX_FLAG_HASH_CACHE);
+   return ctx_wasm_get_context (64*1024);//CTX_FLAG_HASH_CACHE);
 }
 #else
 
@@ -42683,7 +42816,7 @@ static inline void _ctx_string_append_byte (CtxString *string, char  val)
     {
       char *old = string->str;
       int old_len = string->allocated_length;
-      string->allocated_length = CTX_MAX (string->allocated_length * 2, string->length + 2);
+      string->allocated_length = CTX_MAX (string->allocated_length * 1.5, string->length + 2);
       string->str = (char*)ctx_realloc (old, old_len, string->allocated_length);
     }
   string->str[string->length++] = val;
@@ -45438,6 +45571,7 @@ static void ctx_tiled_end_frame (Ctx *ctx)
   }
   mtx_unlock (&tiled->mtx);
   ctx_drawlist_clear (ctx);
+  ctx_handle_events (ctx);
 }
 
 static
@@ -48941,7 +49075,7 @@ typedef struct CtxCbBackend
   Ctx           *ctx;
 
   void (*set_pixels) (Ctx *ctx, void *user_data, 
-                      int x, int y, int w, int h, void *buf, int buf_size);
+                      int x, int y, int w, int h, void *buf);
   void   *set_pixels_user_data;
   int  (*update_fb) (Ctx *ctx, void *user_data);
   void   *update_fb_user_data;
@@ -48955,6 +49089,8 @@ typedef struct CtxCbBackend
 void ctx_cb_set_flags (Ctx *ctx, int flags)
 {
   CtxCbBackend *backend_cb = (CtxCbBackend*)ctx->backend;
+
+#if CTX_CB_ENABLE_LOW_FI
   if (flags & CTX_FLAG_GRAY2)
     flags |= CTX_FLAG_LOWFI;
   if (flags & CTX_FLAG_GRAY4)
@@ -48966,6 +49102,7 @@ void ctx_cb_set_flags (Ctx *ctx, int flags)
 
   if (flags & CTX_FLAG_LOWFI)
     flags |= CTX_FLAG_HASH_CACHE;
+#endif
   backend_cb->flags = flags;
 }
 
@@ -49031,7 +49168,7 @@ ctx_memdebug (CtxCbBackend *cb_backend, int line_no)
                         
 #define CTX_VERIFY_MEM()  do{ctx_memdebug(backend_cb, __LINE__);}while(0)
 #else
-#define CTX_SCRATCH_PAD   1024
+#define CTX_SCRATCH_PAD   0
 #define CTX_VERIFY_MEM()  do{}while(0)
 #endif
 
@@ -49050,8 +49187,10 @@ static int ctx_render_cb (CtxCbBackend *backend_cb,
   
   int width          = x1 - x0 + 1;
   int height         = y1 - y0 + 1;
+#if CTX_CB_ENABLE_LOW_FI
   int byteswap;
   byteswap = (format == CTX_FORMAT_RGB565_BYTESWAPPED);
+#endif
 
   if (!backend_cb->fb)
   {
@@ -49064,9 +49203,10 @@ static int ctx_render_cb (CtxCbBackend *backend_cb,
   fb = backend_cb->fb;
 
   void (*set_pixels) (Ctx *ctx, void *user_data, 
-                      int x, int y, int w, int h, void *buf, int buf_size) =
+                      int x, int y, int w, int h, void *buf) =
     backend_cb->set_pixels;
 
+#if CTX_CB_ENABLE_LOW_FI
   if (flags & CTX_FLAG_LOWFI)
   {
     int scale_factor  = 1;
@@ -49237,8 +49377,7 @@ static int ctx_render_cb (CtxCbBackend *backend_cb,
         }
       }
       set_pixels (ctx, backend_cb->set_pixels_user_data, 
-                  x0, y0, width, render_height, (uint16_t*)scaled,
-                  width * render_height * bpp);
+                  x0, y0, width, render_height, (uint16_t*)scaled);
       y0 += render_height;
       yo += render_height;
     } while (y0 < y1);
@@ -49248,6 +49387,7 @@ static int ctx_render_cb (CtxCbBackend *backend_cb,
     // abort does not happen for low-res update
   }
   else
+#endif
   {
     int render_height = height;
     if (width * render_height > memory_budget / bpp)
@@ -49280,8 +49420,7 @@ static int ctx_render_cb (CtxCbBackend *backend_cb,
         ctx_render_ctx (ctx, ctx);
 
       set_pixels (ctx, set_pixels_user_data, 
-                  x0, y0, width, render_height, (uint16_t*)fb,
-                  width * render_height * bpp);
+                  x0, y0, width, render_height, (uint16_t*)fb);
 
       if (do_intra)
         abort = backend_cb->update_fb (ctx, backend_cb->update_fb_user_data);
@@ -49345,8 +49484,10 @@ ctx_cb_end_frame (Ctx *ctx)
 
   int tile_width = width / CTX_HASH_COLS;
   int tile_height = height / CTX_HASH_ROWS;
+#if CTX_CB_ENABLE_LOW_FI
   if (cb_backend->flags & (CTX_FLAG_GRAY2|CTX_FLAG_GRAY4|CTX_FLAG_GRAY8|CTX_FLAG_RGB332))
       cb_backend->flags|=CTX_FLAG_LOWFI;
+#endif
 
   if (cb_backend->flags & CTX_FLAG_SHOW_FPS)
   {
@@ -49364,7 +49505,7 @@ ctx_cb_end_frame (Ctx *ctx)
     {
       char buf[22];
       float fps = 1.0f/((cur_time-prev_time)/1000.0f);
-      ctx_move_to (ctx, width * 0.5, y);
+      ctx_move_to (ctx, width * 0.5f, y);
       ctx_text_align (ctx, CTX_TEXT_ALIGN_CENTER);
       sprintf (buf, "%2.1ffps", (double)fps);
       ctx_text (ctx, buf);
@@ -49424,6 +49565,7 @@ ctx_cb_end_frame (Ctx *ctx)
 
       int in_low_res = 0;
       int old_flags = cb_backend->flags;
+#if CTX_CB_ENABLE_LOW_FI
       if (cb_backend->flags & CTX_FLAG_LOWFI)
       {
         in_low_res = 1; // default to assume we're in low res
@@ -49471,6 +49613,7 @@ ctx_cb_end_frame (Ctx *ctx)
             }
         }
       }
+#endif
 
       ctx_pop_backend (ctx); // done with hasher
       if (dirty_tiles)
@@ -49491,8 +49634,8 @@ ctx_cb_end_frame (Ctx *ctx)
          }
 #endif
 
-         //int width = x1 - x0 + 1;
-         //int height = y1 - y0 + 1;
+         int width = x1 - x0 + 1;
+         int height = y1 - y0 + 1;
          int abort = 0;
          int abortable = 1;
 
@@ -49525,6 +49668,26 @@ ctx_cb_end_frame (Ctx *ctx)
          {
            tile_no = 0;
 
+           if (width * height * bpp <= cb_backend->memory_budget)
+           {
+             // we have enough memory to render all in one go
+             active_mask = 0;
+             for (int row = cb_backend->min_row; row <= cb_backend->max_row; row++)
+               for (int col = cb_backend->min_col; col <= cb_backend->max_col; col++)
+               {
+                 int tile_no = row * CTX_HASH_COLS + col;
+                 cb_backend->res[tile_no]=0;
+                 cb_backend->hashes[tile_no] = hashes[tile_no];
+                 active_mask |= (1<<tile_no);
+               }
+              abort = ctx_render_cb (cb_backend, x0, y0, x1, y1, active_mask);
+              if (!abortable)
+                abort = 0;
+           }
+           else
+           {
+              // render row-by-row (no merging of rows)
+
            for (int row = 0; row < CTX_HASH_ROWS; row++)
            {
              for (int col = 0; col < CTX_HASH_COLS; col++)
@@ -49538,10 +49701,10 @@ ctx_cb_end_frame (Ctx *ctx)
                if ((new_hash != cb_backend->hashes[tile_no]) ||
                    cb_backend->res[tile_no])
                {
-                    int x0 = col * tile_width;
-                    int y0 = row * tile_height;
-                    int x1 = x0 +  tile_width-1;
-                    int y1 = y0 +  tile_height-1;
+                    int tx0 = col * tile_width;
+                    int ty0 = row * tile_height;
+                    int tx1 = tx0 +  tile_width-1;
+                    int ty1 = ty0 +  tile_height-1;
 
 #if 1
              int max_tiles = (cb_backend->memory_budget / tile_dim);
@@ -49554,7 +49717,7 @@ ctx_cb_end_frame (Ctx *ctx)
                       {
                         active_mask |= (1 << (tile_no+used_tiles));
                         used_tiles ++;
-                        x1 += (ctx_width (ctx)/CTX_HASH_COLS);
+                        tx1 += (ctx_width (ctx)/CTX_HASH_COLS);
                       }
                       else
                       {
@@ -49564,7 +49727,7 @@ ctx_cb_end_frame (Ctx *ctx)
 #endif
 
 
-                    abort = ctx_render_cb (cb_backend, x0, y0, x1, y1, active_mask);
+                    abort = ctx_render_cb (cb_backend, tx0, ty0, tx1, ty1, active_mask);
                     {
                       for (int i = 0; i < used_tiles; i ++)
                       {
@@ -49578,6 +49741,8 @@ ctx_cb_end_frame (Ctx *ctx)
                   }
                }
            }
+           }
+
              }
            }
       cb_backend->flags = old_flags;
@@ -49592,8 +49757,7 @@ ctx_cb_end_frame (Ctx *ctx)
 
 Ctx *ctx_new_cb (int width, int height, CtxPixelFormat format,
                  void (*set_pixels) (Ctx *ctx, void *user_data, 
-                                     int x, int y, int w, int h, void *buf,
-                                     int buf_size),
+                                     int x, int y, int w, int h, void *buf),
                  void *set_pixels_user_data,
                  int (*update_fb) (Ctx *ctx, void *user_data),
                  void *update_fb_user_data,
@@ -49628,7 +49792,7 @@ Ctx *ctx_new_cb (int width, int height, CtxPixelFormat format,
 
 #if CTX_TFT_ESPI
 
-static void ctx_tft_set_pixels (Ctx *ctx, void *user_data, int x, int y, int w, int h, void *buf, int buf_size)
+static void ctx_tft_set_pixels (Ctx *ctx, void *user_data, int x, int y, int w, int h, void *buf)
 {
   TFT_eSPI *tft = (TFT_eSPI*)user_data;
   tft->pushRect (x, y, w, h, (uint16_t*)buf);
@@ -49761,9 +49925,9 @@ int update_fb (Ctx *ctx, void *user_data)
   );
 
 #ifdef EMSCRIPTEN
-#ifdef ASYNCIFY
+//#ifdef ASYNCIFY
    emscripten_sleep(0);
-#endif
+//#endif
 #endif
 
    int ret = 0;
@@ -49810,7 +49974,7 @@ int update_fb (Ctx *ctx, void *user_data)
 EMSCRIPTEN_KEEPALIVE
 uint8_t wasm_scratch[1024*1024*4];
 
-static void set_pixels (Ctx *ctx, void *user_data, int x0, int y0, int w, int h, void *buf, int buf_size)
+static void set_pixels (Ctx *ctx, void *user_data, int x0, int y0, int w, int h, void *buf)
 {
   uint8_t *src = (uint8_t*)buf;
   int in_w = w;
@@ -49831,6 +49995,8 @@ static void set_pixels (Ctx *ctx, void *user_data, int x0, int y0, int w, int h,
     ctx_RGB565_BS_to_RGBA8 (NULL, x0, src + i * in_w * 2,
                     wasm_scratch + i * w * 4, w);
   }
+  if (w <= 0 || h <= 0)
+    return;
 
   EM_ASM(
     var x0 = $0;
@@ -52978,8 +53144,8 @@ ctx_draw_texture_clipped  (Ctx *ctx, const char *eid,
     }
 
     {
-      if (clip_width>0) tex_width = clip_width;
-      if (clip_height>0) tex_height = clip_height;
+      if (clip_width>0) tex_width = (int)clip_width;
+      if (clip_height>0) tex_height = (int)clip_height;
       ctx_rectangle (ctx, x, y, width, height);
       ctx_save (ctx);
       ctx_texture (ctx, eid, x-(clip_x) * (width/tex_width), y-clip_y * (height
@@ -54415,6 +54581,9 @@ static Ctx *ctx_new_ui (int width, int height, const char *backend);
 #if CTX_PICO
 Ctx *ctx_pico_init (void);
 #endif
+#if CTX_ESP
+Ctx *esp_ctx (void);
+#endif
 
 CTX_EXPORT Ctx *
 ctx_new (int width, int height, const char *backend)
@@ -54422,6 +54591,9 @@ ctx_new (int width, int height, const char *backend)
 #if CTX_PICO
   return ctx_pico_init ();
 #endif
+#if CTX_ESP
+  return esp_ctx();
+#endif
 
 #if CTX_EVENTS
   if (backend && !ctx_strcmp (backend, "drawlist"))
@@ -55712,12 +55884,18 @@ utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
 
 typedef struct _VtLine   VtLine;
 
+#if CTX_VT_STYLE_SIZE==32
+typedef uint32_t vt_style_t;
+#else
+typedef uint64_t vt_style_t;
+#endif
+
 struct _VtLine
 {
   CtxString string;
   /* line extends string, permitting string ops to operate on it  */
 
-  uint64_t *style;
+  vt_style_t *style;
 
   void     *ctx; // each line can have an attached ctx context;
   char     *prev;
@@ -55774,7 +55952,7 @@ static inline void vt_line_set_style (VtLine *string, int pos, uint64_t style)
     return;
   if (pos >= string->style_size)
     {
-      int new_size = pos + 16;
+      int new_size = pos + 8;
       string->style = ctx_realloc (string->style, string->style_size, new_size * sizeof (uint64_t) );
       memset (&string->style[string->style_size], 0, (new_size - string->style_size) * sizeof (uint64_t) );
       string->style_size = new_size;
@@ -55973,7 +56151,7 @@ VtLine *vt_line_new_with_size (const char *initial, int initial_size)
   ctx_string_init (string, initial_size);
   if (initial)
     { ctx_string_append_str (string, initial); }
-  line->style = ctx_calloc (sizeof (uint64_t), initial_size);
+  line->style = ctx_calloc (sizeof (vt_style_t), initial_size);
   line->style_size = initial_size;
   string->is_line = 1;
   return line;
@@ -56129,11 +56307,14 @@ struct _VT
   int mouse_all;
   int mouse_decimal;
 
-
-  uint8_t    utf8_holding[64]; /* only 4 needed for utf8 - but it's purpose
+#if CTX_PTY
+  uint8_t    utf8_holding[64];
+#else
+  uint8_t    utf8_holding[4]; /* only 4 needed for utf8 - but it's purpose
                                  is also overloaded for ctx journal command
                                  buffering , and the bigger sizes for the svg-like
                                  ctx parsing mode */
+#endif
   int        utf8_expected_bytes;
   int        utf8_pos;
 
@@ -56283,7 +56464,7 @@ void        vt_paste              (VT *vt, const char *str);
 #if CTX_PTY
 #define DEFAULT_SCROLLBACK   (1<<13)
 #else
-#define DEFAULT_SCROLLBACK   (2)
+#define DEFAULT_SCROLLBACK   (1)
 #endif
 #define DEFAULT_ROWS         24
 #define DEFAULT_COLS         80
@@ -57942,7 +58123,7 @@ void vt_audio (VT *vt, const char *command)
  */
 
 int ctx_dummy_in_len = 0;
-#if CTX_TERMINAL_EVENTS
+//#if CTX_TERMINAL_EVENTS
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -57978,7 +58159,6 @@ int ctx_dummy_in_len = 0;
 //#include "ctx-clients.h"
 
 
-
 #define VT_LOG_INFO     (1<<0)
 #define VT_LOG_CURSOR   (1<<1)
 #define VT_LOG_COMMAND  (1<<2)
@@ -58544,7 +58724,9 @@ static void vt_init (VT *vt, int width, int height, float font_size, float line_
   static int signal_installed = 0;
   if (!signal_installed)
   {
+#if CTX_PTY
     signal (SIGCHLD,ctx_clients_signal_child);
+#endif
     signal_installed = 1;
   }
   vt->id                 = id;
@@ -58746,8 +58928,8 @@ int     em_waitdata (void *serial_obj, int timeout)
 
 #endif
 
-#define CTX_VT_INBUFSIZE  128
-#define CTX_VT_OUTBUFSIZE 128
+#define CTX_VT_INBUFSIZE  400
+#define CTX_VT_OUTBUFSIZE 32
 
 static char ctx_dummy_inbuf[CTX_VT_INBUFSIZE]="";
 static char ctx_dummy_outbuf[CTX_VT_OUTBUFSIZE]="";
@@ -58757,8 +58939,18 @@ static int ctx_dummy_out_len = 0;
 static int ctx_dummy_out_pos = 0;
 static int ctx_dummy_out_read_pos = 0;
 
+int ctx_vt_available (Ctx *ctx)
+{
+  return CTX_VT_INBUFSIZE - ctx_dummy_in_len - 1;
+}
+
 void ctx_vt_write (Ctx *ctx, uint8_t byte)
 {
+#if 0
+  while (ctx_dummy_in_len > CTX_VT_INBUFSIZE/2)
+  {
+  }
+#endif
   if (ctx_dummy_in_len < CTX_VT_INBUFSIZE)
   {
     ctx_dummy_inbuf[ctx_dummy_in_pos++] = byte;
@@ -58788,6 +58980,13 @@ int ctx_vt_read (Ctx *ctx)
   return ret;
 }
 
+int ctx_vt_cursor_y (CtxClient *client)
+{
+  if (!client) return 0;
+  VT *vt = ctx_client_vt (client);
+  if (!vt) return 0;
+  return vt_get_cursor_y (vt);
+}
 
 static ssize_t ctx_dummy_write (void *s, const void *buf, size_t count)
 {
@@ -61258,15 +61457,15 @@ ESC [ 2 0 0 ~,
 #define VT2020  (XTERM|COMPAT_FLAG_GRAPHICS|COMPAT_FLAG_AUDIO)
 
 
-            static Sequence sequences[]=
+static const Sequence sequences[]=
   {
     /*
       prefix suffix  command */
     //{"B",  0,  vtcmd_break_permitted},
     //{"C",  0,  vtcmd_nobreak_here},
     {"D", 0,    vtcmd_index, VT100}, /* args: id:IND Index  */
-    {"E",  0,   vtcmd_next_line}, /* ref:none id:  Next line */
-    {"_", 'G',  vtcmd_graphics},
+    {"E",  0,   vtcmd_next_line, 0}, /* ref:none id:  Next line */
+    {"_", 'G',  vtcmd_graphics, 0},
     {"H",   0,  vtcmd_horizontal_tab_set, VT100}, /* id:HTS Horizontal Tab Set */
 
     //{"I",  0,  vtcmd_char_tabulation_with_justification},
@@ -61284,13 +61483,13 @@ ESC [ 2 0 0 ~,
     /* these need to occur before vtcmd_preceding_line to have precedence */
     {"[0 F", 0, vtcmd_justify, ANSI},
     {"[1 F", 0, vtcmd_justify, ANSI},
-    {"[2 F", 0, vtcmd_justify},
-    {"[3 F", 0, vtcmd_justify},
-    {"[4 F", 0, vtcmd_justify},
-    {"[5 F", 0, vtcmd_justify},
-    {"[6 F", 0, vtcmd_justify},
-    {"[7 F", 0, vtcmd_justify},
-    {"[8 F", 0, vtcmd_justify},
+    {"[2 F", 0, vtcmd_justify, 0},
+    {"[3 F", 0, vtcmd_justify, 0},
+    {"[4 F", 0, vtcmd_justify, 0},
+    {"[5 F", 0, vtcmd_justify, 0},
+    {"[6 F", 0, vtcmd_justify, 0},
+    {"[7 F", 0, vtcmd_justify, 0},
+    {"[8 F", 0, vtcmd_justify, 0},
 // XXX missing DECIC DECDC  insert and delete column
     {"[", 'A', vtcmd_cursor_up, VT100},   /* args:Pn    id:CUU Cursor Up */
     {"[",  'B', vtcmd_cursor_down, VT100}, /* args:Pn    id:CUD Cursor Down */
@@ -61300,9 +61499,9 @@ ESC [ 2 0 0 ~,
     {"[",  'k', vtcmd_cursor_up, ANSI}, /* args:Pn ref:none id:VPB Vertical Position Backward */
     {"[",  'E', vtcmd_next_line, VT100}, /* args:Pn id:CNL Cursor Next Line */
     {"[",  'F', vtcmd_cursor_preceding_line, VT100}, /* args:Pn id:CPL Cursor Preceding Line */
-    {"[",  'G', vtcmd_horizontal_position_absolute}, /* args:Pn id:CHA Cursor Horizontal Absolute */
+    {"[",  'G', vtcmd_horizontal_position_absolute, 0}, /* args:Pn id:CHA Cursor Horizontal Absolute */
     {"[",  'H', vtcmd_cursor_position, VT100}, /* args:Pl;Pc id:CUP Cursor Position */
-    {"[",  'I', vtcmd_insert_n_tabs}, /* args:Pn id:CHT Cursor Horizontal Forward Tabulation */
+    {"[",  'I', vtcmd_insert_n_tabs, 0}, /* args:Pn id:CHT Cursor Horizontal Forward Tabulation */
     {"[",  'J', vtcmd_erase_in_display, VT100}, /* args:Ps id:ED Erase in Display */
     {"[",  'K', vtcmd_erase_in_line, VT100}, /* args:Ps id:EL Erase in Line */
     {"[",  'L', vtcmd_insert_blank_lines, VT102}, /* args:Pn id:IL Insert Line */
@@ -61312,7 +61511,7 @@ ESC [ 2 0 0 ~,
     {"[",  'P', vtcmd_delete_n_chars, VT102}, /* args:Pn id:DCH Delete Character */
     // [ Q is SEE - Set editing extent
     // [ R is CPR - active cursor position report
-    {"[?", 'S', vtcmd_sixel_related_req},
+    {"[?", 'S', vtcmd_sixel_related_req, 0},
     {"[",  'S', vtcmd_scroll_up, VT100},   /* args:Pn id:SU Scroll Up */
     {"[",  'T', vtcmd_scroll_down, VT100}, /* args:Pn id:SD Scroll Down */
     {"[",/*SP*/'U', vtcmd_set_line_home, ANSI}, /* args:PnSP id=SLH Set Line Home */
@@ -61320,16 +61519,16 @@ ESC [ 2 0 0 ~,
     // [ W is cursor tabulation control
     // [ Pn Y  - cursor line tabulation
     //
-    {"[",  'X', vtcmd_erase_n_chars}, /* args:Pn id:ECH Erase Character */
-    {"[",  'Z', vtcmd_rev_n_tabs},    /* args:Pn id:CBT Cursor Backward Tabulation */
-    {"[",  '^', vtcmd_scroll_down}  , /* muphry alternate from ECMA */
+    {"[",  'X', vtcmd_erase_n_chars, 0}, /* args:Pn id:ECH Erase Character */
+    {"[",  'Z', vtcmd_rev_n_tabs, 0},    /* args:Pn id:CBT Cursor Backward Tabulation */
+    {"[",  '^', vtcmd_scroll_down, 0}  , /* muphry alternate from ECMA */
     {"[",  '@', vtcmd_insert_character, VT102}, /* args:Pn id:ICH Insert Character */
 
     {"[",  'a', vtcmd_cursor_forward, ANSI}, /* args:Pn id:HPR Horizontal Position Relative */
     {"[",  'b', vtcmd_cursor_forward, ANSI}, /* REP previous char XXX incomplete */
-    {"[",  'c', vtcmd_report}, /* ref:none id:DA args:... Device Attributes */
-    {"[",  'd', vtcmd_goto_row},       /* args:Pn id:VPA Vertical Position Absolute  */
-    {"[",  'e', vtcmd_cursor_down},    /* args:Pn id:VPR Vertical Position Relative */
+    {"[",  'c', vtcmd_report, 0}, /* ref:none id:DA args:... Device Attributes */
+    {"[",  'd', vtcmd_goto_row, 0},       /* args:Pn id:VPA Vertical Position Absolute  */
+    {"[",  'e', vtcmd_cursor_down, 0},    /* args:Pn id:VPR Vertical Position Relative */
     {"[",  'f', vtcmd_cursor_position, VT100}, /* args:Pl;Pc id:HVP Cursor Position */
     {"[g", 0,   vtcmd_clear_current_tab, VT100}, /* id:TBC clear current tab */
     {"[0g", 0,  vtcmd_clear_current_tab, VT100}, /* id:TBC clear current tab */
@@ -61347,10 +61546,10 @@ ESC [ 2 0 0 ~,
 
     {"[",  'h', vtcmd_set_mode, VT100},   /* args:Pn[;...] id:SM Set Mode */
     {"[",  'l', vtcmd_set_mode, VT100}, /* args:Pn[;...]  id:RM Reset Mode */
-    {"[",  't', vtcmd_set_t},
+    {"[",  't', vtcmd_set_t, 0},
     {"[",  'q', vtcmd_set_led, VT100}, /* args:Ps id:DECLL Load LEDs */
-    {"[",  'x', vtcmd_report}, /* ref:none id:DECREQTPARM */
-    {"[",  'z', vtcmd_DECELR}, /* ref:none id:DECELR set locator res  */
+    {"[",  'x', vtcmd_report, 0}, /* ref:none id:DECREQTPARM */
+    {"[",  'z', vtcmd_DECELR, 0}, /* ref:none id:DECELR set locator res  */
 
     {"5",   0,  vtcmd_char_at_cursor, VT300}, /* ref:none id:DECXMIT */
     {"6",   0,  vtcmd_back_index, VT400}, /* id:DECBI Back index (hor. scroll) */
@@ -61362,17 +61561,17 @@ ESC [ 2 0 0 ~,
     //{"%G",0,  vtcmd_set_default_font}, // set_alternate_font
 
 
-    {"(0",  0,   vtcmd_set_charmap},
-    {"(1",  0,   vtcmd_set_charmap},
-    {"(2",  0,   vtcmd_set_charmap},
-    {"(A",  0,   vtcmd_set_charmap},
-    {"(B",  0,   vtcmd_set_charmap},
-    {")0",  0,   vtcmd_set_charmap},
-    {")1",  0,   vtcmd_set_charmap},
-    {")2",  0,   vtcmd_set_charmap},
-    {")A",  0,   vtcmd_set_charmap},
-    {")B",  0,   vtcmd_set_charmap},
-    {"%G",  0,   vtcmd_set_charmap},
+    {"(0",  0,   vtcmd_set_charmap, 0},
+    {"(1",  0,   vtcmd_set_charmap, 0},
+    {"(2",  0,   vtcmd_set_charmap,0},
+    {"(A",  0,   vtcmd_set_charmap,0},
+    {"(B",  0,   vtcmd_set_charmap,0},
+    {")0",  0,   vtcmd_set_charmap,0},
+    {")1",  0,   vtcmd_set_charmap,0},
+    {")2",  0,   vtcmd_set_charmap,0},
+    {")A",  0,   vtcmd_set_charmap,0},
+    {")B",  0,   vtcmd_set_charmap,0},
+    {"%G",  0,   vtcmd_set_charmap,0},
 
     {"#3",  0,   vtcmd_set_double_width_double_height_top_line, VT100}, /*id:DECDHL Top half of double-width, double-height line */
     {"#4",  0,   vtcmd_set_double_width_double_height_bottom_line, VT100}, /*id:DECDHL Bottom half of double-width, double-height line */
@@ -61380,16 +61579,16 @@ ESC [ 2 0 0 ~,
     {"#6",  0,   vtcmd_set_double_width_single_height_line, VT100}, /* id:DECDWL Double-width line */
 
     {"#8",  0,   vtcmd_screen_alignment_display, VT100}, /* id:DECALN Screen Alignment Pattern */
-    {"=",   0,   vtcmd_ignore},  // keypad mode change
-    {">",   0,   vtcmd_ignore},  // keypad mode change
+    {"=",   0,   vtcmd_ignore,0},  // keypad mode change
+    {">",   0,   vtcmd_ignore,0},  // keypad mode change
     {"c",   0,   vtcmd_reset_to_initial_state, VT100}, /* id:RIS Reset to Initial State */
-    {"[!", 'p',  vtcmd_ignore},       // soft reset?
-    {"[",  'p',  vtcmd_request_mode}, /* args:Pa$ id:DECRQM Request ANSI Mode */
+    {"[!", 'p',  vtcmd_ignore,0},       // soft reset?
+    {"[",  'p',  vtcmd_request_mode,0}, /* args:Pa$ id:DECRQM Request ANSI Mode */
 #if 0
-    {"[?",  'p',  vtcmd_request_mode}, /* args:Pd$ id:DECRQM Request DEC Mode */
+    {"[?",  'p',  vtcmd_request_mode,0}, /* args:Pd$ id:DECRQM Request DEC Mode */
 #endif
 
-    {NULL, 0, NULL}
+    {NULL, 0, NULL, 0}
   };
 
   static void handle_sequence (VT *vt, const char *sequence)
@@ -61795,6 +61994,7 @@ void vt_gfx (VT *vt, const char *command)
           vt->gfx.buf_size = vt->gfx.buf_width * vt->gfx.buf_height *
                              (vt->gfx.format == 24 ? 3 : 4);
         }
+#if 0
       if (vt->gfx.compression == 'z')
         {
           //vt->gfx.buf_size)
@@ -61817,6 +62017,7 @@ void vt_gfx (VT *vt, const char *command)
           vt->gfx.data_size = actual_uncompressed_size;
           vt->gfx.compression = 0;
         }
+#endif
 #if CTX_STB_IMAGE
       if (vt->gfx.format == 100)
         {
@@ -65973,7 +66174,7 @@ void ctx_client_mouse_event (CtxEvent *event, void *data, void *data2)
   if (vt)
   {
   if ((!vt->in_alt_screen) &&
-      (event->x > vt->width - vt->cw * 1.5 || scrollbar_down) &&
+      (event->x > vt->width - vt->cw * 3.5 || scrollbar_down) &&
       (event->type == CTX_DRAG_MOTION ||
       event->type == CTX_DRAG_PRESS ||
       event->type == CTX_DRAG_RELEASE))
@@ -66058,7 +66259,7 @@ void vt_mouse_event (CtxEvent *event, void *data, void *data2)
   int device_no = event->device_no;
   char buf[128]="";
   if ((!vt->in_alt_screen) &&
-      (event->x > vt->width - vt->cw * 1.5 || scrollbar_down) &&
+      (event->x > vt->width - vt->cw * 3.5 || scrollbar_down) &&
       (event->type == CTX_DRAG_MOTION ||
       event->type == CTX_DRAG_PRESS ||
       event->type == CTX_DRAG_RELEASE))
@@ -66297,24 +66498,25 @@ void vt_draw (VT *vt, Ctx *ctx, double x0, double y0)
   //if (vt->scroll || full)
     {
       ctx_begin_path (ctx);
-#if CTX_PTY
+//#if CTX_PTY
       ctx_rectangle (ctx, 0, 0, vt->width, //(vt->cols) * vt->cw,
                      (vt->rows) * vt->ch);
       if (vt->reverse_video)
         {
-          itk_style_color (ctx, "terminal-bg-reverse");
+          //itk_style_color (ctx, "terminal-bg-reverse");
+          ctx_rgba (ctx, 1.0,1.0,1.0,1.0f);
           ctx_fill  (ctx);
         }
       else
         {
-          itk_style_color (ctx, "terminal-bg");
-          //ctx_rgba (ctx,0,0,0,1.0f);
+          //itk_style_color (ctx, "terminal-bg");
+          ctx_rgba (ctx,0,0,0,1.0f);
           ctx_fill  (ctx);
         }
-#else
-          //ctx_rgba (ctx,0,0,0,1.0f);
-          ctx_fill  (ctx);
-#endif
+//#else
+//          ctx_rgba (ctx,0,0,0,1.0f);
+//          ctx_fill  (ctx);
+//#endif
       if (vt->scroll != 0.0f)
         ctx_translate (ctx, 0.0, vt->ch * vt->scroll);
     }
@@ -66682,10 +66884,8 @@ void vt_set_local (VT *vt, int local)
   vt->local_editing = local;
 }
 
-#if CTX_PTY
 static unsigned long prev_press_time = 0;
 static int short_count = 0;
-#endif
 
 void terminal_set_primary (const char *text)
 {
@@ -66695,9 +66895,7 @@ void terminal_set_primary (const char *text)
 }
 
 void terminal_long_tap (Ctx *ctx, VT *vt);
-#if CTX_PTY
 static int long_tap_cb_id = 0;
-#endif
 static int single_tap (Ctx *ctx, void *data)
 {
 #if 0 // XXX
@@ -66710,7 +66908,7 @@ static int single_tap (Ctx *ctx, void *data)
 
 void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, int y, int px_x, int px_y)
 {
-#if CTX_PTY
+//#if CTX_PTY
  char buf[64]="";
  int button_state = 0;
  ctx_client_rev_inc (vt->client);
@@ -66927,7 +67125,7 @@ void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, in
      vt_write (vt, buf, strlen (buf) );
      fsync (vt->vtpty.pty);
    }
-#endif
+//#endif
 }
 
 pid_t vt_get_pid (VT *vt)
@@ -66940,7 +67138,7 @@ void vt_set_ctx (VT *vt, Ctx *ctx)
   vt->root_ctx = ctx;
 }
 
-#endif
+//#endif
 #endif
 #endif
 
diff --git a/components/micropython/usermodule/mp_uctx.c b/components/micropython/usermodule/mp_uctx.c
index 33361d87767fea100811222d48041e5d4719ee35..8fb83ced0607d9effbbb0f5b755c4b393f6d8672 100644
--- a/components/micropython/usermodule/mp_uctx.c
+++ b/components/micropython/usermodule/mp_uctx.c
@@ -551,8 +551,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_ctx_tinyvg_draw_obj, mp_ctx_tinyvg_draw);
 /* CTX API functions }}} */
 
 static void mp_ctx_set_pixels(Ctx *ctx, void *user_data, int x_in, int y_in,
-                              int width_in, int height_in, void *buf_in,
-                              int buf_size) {
+                              int width_in, int height_in, void *buf_in) {
+    int buf_size = width_in * height_in * 2;  // XXX : not valid for non-16bpp!
     mp_obj_t args[5] = { mp_obj_new_int(x_in), mp_obj_new_int(y_in),
                          mp_obj_new_int(width_in), mp_obj_new_int(height_in),
                          mp_obj_new_memoryview(BYTEARRAY_TYPECODE, buf_size,
diff --git a/components/st3m/st3m_gfx.c b/components/st3m/st3m_gfx.c
index 2b7c5e9a251cfa986c6d6aef113b739f540bf2b5..2cc1ff2b9061363b9e7e2e25ad56fae09e908727 100644
--- a/components/st3m/st3m_gfx.c
+++ b/components/st3m/st3m_gfx.c
@@ -911,7 +911,7 @@ void st3m_gfx_show_textview(st3m_gfx_textview_t *tv) {
 }
 
 static void set_pixels_ctx(Ctx *ctx, void *user_data, int x, int y, int w,
-                           int h, void *buf, int buf_size) {
+                           int h, void *buf) {
     uint16_t *src = buf;
     for (int scan = y; scan < y + h; scan++) {
         uint16_t *dst = (uint16_t *)&st3m_fb[(scan * 240 + x) * 2];