diff --git a/python_payload/main.py b/python_payload/main.py
index 50d64efd90b39f78ca2d738845b9ef986b542dbf..fcd8a927efe1d2258fa74074aeeede13e2563209 100644
--- a/python_payload/main.py
+++ b/python_payload/main.py
@@ -13,16 +13,12 @@ import st4m
 from st4m.goose import Optional, List, ABCBase, abstractmethod
 from st4m.ui.view import View, ViewManager, ViewTransitionBlend
 from st4m.ui.menu import (
-    MenuItem,
-    MenuController,
     MenuItemBack,
     MenuItemForeground,
     MenuItemNoop,
 )
 
-from st4m import Responder, InputState, Ctx
-
-# from apps import flow3r
+from st4m.ui.elements.menus import FlowerMenu, SimpleMenu
 
 log.info("import apps done")
 log.info(f"free memory: {gc.mem_free()}")
@@ -36,255 +32,8 @@ log.info("calibrating captouch, reset volume")
 captouch.calibration_request()
 audio.set_volume_dB(0)
 
-import math, random
-from st3m.ui import xy_from_polar
-
-WIDTH = 240
-HEIGHT = 240
-
-# Define a few RGB (0.0 to 1.0) colors
-BLACK = (0, 0, 0)
-RED = (1, 0, 0)
-GREEN = (0, 1, 0)
-BLUE = (0, 0, 1)
-WHITE = (1, 1, 1)
-GREY = (0.5, 0.5, 0.5)
-GO_GREEN = (63 / 255, 255 / 255, 33 / 53)
-PUSH_RED = (251 / 255, 72 / 255, 196 / 255)
-
-tau = 2 * math.pi
-
 vm = ViewManager(ViewTransitionBlend())
 
-
-def lerp(a: float, b: float, v: float) -> float:
-    if v <= 0:
-        return a
-    if v >= 1.0:
-        return b
-    return a + (b - a) * v
-
-
-class GroupRing(Responder):
-    def __init__(self, r=100, x=0, y=0):
-        self.r = r
-        self.x = x
-        self.y = y
-        self.items_ring = []
-        self.item_center = None
-        self.angle_offset = 0
-        self.ts = 0.0
-
-    def think(self, ins: InputState, delta_ms: int) -> None:
-        self.ts += delta_ms
-        self.item_center.think(ins, delta_ms)
-        for item in self.items_ring:
-            item.think(ins, delta_ms)
-
-    def draw(self, ctx: Ctx) -> None:
-        if self.item_center:
-            self.item_center.has_highlight = False
-            self.item_center.draw(ctx)
-            # self.items_ring[0].draw(ctx)
-
-        # ctx.save()
-        for index, item in enumerate(self.items_ring):
-            if item is None:
-                continue
-            angle = tau / len(self.items_ring) * index + self.angle_offset
-            (x, y) = xy_from_polar(self.r, angle)
-            ctx.save()
-            # ctx.translate(self.x + x, self.y + y)
-            ctx.rotate(-angle).translate(0, self.r).rotate(math.pi)
-            item.draw(ctx)
-            ctx.restore()
-        # ctx.restore()
-
-
-class FlowerIcon(Responder):
-    """
-    A flower icon
-    """
-
-    def __init__(self, label="?") -> None:
-        self.x = 0.0
-        self.y = 0.0
-        self.size = 50.0
-        self.ts = 1.0
-        self.bg = (random.random(), random.random(), random.random())
-        self.label = label
-
-        self.highlighted = False
-        self.rotation_time = 0.0
-
-        self.petal_count = random.randint(2, 3)
-        self.petal_color = (random.random(), random.random(), random.random())
-        self.phi_offset = random.random()
-        self.size_offset = random.randint(0, 20)
-
-    def think(self, ins: InputState, delta_ms: int) -> None:
-        self.ts += delta_ms
-        pass
-
-    def draw(self, ctx: Ctx) -> None:
-        x = self.x
-        y = self.y
-        petal_size = 0
-        if self.petal_count:
-            petal_size = 2.3 * self.size / self.petal_count + self.size_offset
-
-        hs = 5
-        # print(self.ts)
-        ctx.save()
-        ctx.move_to(x, y)
-        ctx.text_align = ctx.CENTER
-        ctx.text_baseline = ctx.MIDDLE
-        ctx.font_size = self.size / 3
-        ctx.line_width = 5
-        if self.rotation_time:
-            phi_rotate = tau * ((self.ts % self.rotation_time) / self.rotation_time)
-        else:
-            phi_rotate = 0
-        for i in range(self.petal_count):
-            # ctx.save()
-
-            phi = (tau / self.petal_count * i + self.phi_offset + phi_rotate) % tau
-            r = self.size / 2
-            (x_, y_) = xy_from_polar(r, phi)
-
-            size_offset = abs(math.pi - (phi + math.pi) % tau) * 5
-            ctx.move_to(x + x_, y + y_)
-            if self.highlighted:
-                # ctx.move_to(x + x_ - petal_size / 2 - size_offset - 5, y + y_)
-                ctx.arc(x + x_, y + y_, petal_size / 2 + size_offset + 1, 0, tau, 0)
-                ctx.rgb(*GO_GREEN).stroke()
-
-            ctx.arc(x + x_, y + y_, petal_size / 2 + size_offset, 0, tau, 0)
-            ctx.rgb(*self.petal_color).fill()
-            # ctx.restore()
-        ctx.move_to(x, y)
-        if self.highlighted:
-            ctx.arc(x, y, self.size / 2, 0, tau, 1)
-            ctx.rgb(*GO_GREEN).stroke()
-
-        ctx.arc(x, y, self.size / 2, 0, tau, 0)
-        ctx.rgb(*self.bg).fill()
-
-        # label
-        # y += self.size / 3
-        w = max(self.size, ctx.text_width(self.label) + 10)
-        h = self.size / 3 + 8
-        if False and self.highlighted:
-            ctx.rgb(*BLACK).move_to(x, y - height / 2).round_rectangle(
-                x - width / 2, y - height / 2, width, height, width // 2
-            ).fill()
-            ctx.rgb(*GO_GREEN).move_to(x, y).text(self.label)
-        else:
-            ctx.save()
-            ctx.translate(0, self.size / 3)
-            ctx.rgb(*PUSH_RED).round_rectangle(
-                x - w / 2, y - h / 2, w, h, w // 2
-            ).fill()
-
-            ctx.rgb(*BLACK).move_to(x, y).text(self.label)
-            ctx.restore()
-
-        ctx.restore()
-
-
-class FlowerMenu(MenuController):
-    """
-    A circular menu with flowers.
-    """
-
-    __slots__ = (
-        "_ts",
-        "_sun",
-    )
-
-    def __init__(self, items: List[MenuItem], vm: ViewManager, name="flow3r") -> None:
-        self._ts = 0
-        self.name = name
-        self.ui = GroupRing(r=80)
-        for item in items:
-            self.ui.items_ring.append(FlowerIcon(label=item.label()))
-        super().__init__(items, vm)
-        self._scroll_controller.wrap = True
-
-        self.icon = FlowerIcon(label=self.name)
-        self.icon.rotation_time = -5000
-        self.ui.item_center = self.icon
-
-        self.angle = 0
-        self.angle_step = 0.2
-
-    def think(self, ins: InputState, delta_ms: int) -> None:
-        super().think(ins, delta_ms)
-        self.ui.think(ins, delta_ms)
-        self._ts += delta_ms
-
-    def draw(self, ctx: Ctx) -> None:
-        ctx.gray(0)
-        ctx.rectangle(-120, -120, 240, 240).fill()
-        for item in self.ui.items_ring:
-            item.highlighted = False
-            item.rotation_time = 10000
-        current = self._scroll_controller.current_position()
-        self.ui.items_ring[int(current)].highlighted = True
-        self.ui.items_ring[int(current)].rotation_time = 3000
-        self.ui.angle_offset = math.pi - (tau * current / len(self.ui.items_ring))
-
-        self.ui.draw(ctx)
-        # print("here")
-        # ctx.font_size = 40
-        # ctx.text_align = ctx.CENTER
-        # ctx.text_baseline = ctx.MIDDLE
-
-        # angle_per_item = 0.4
-
-        # current = self._scroll_controller.current_position()
-
-        # for ix, item in enumerate(self._items):
-        #    rot = (ix - current) * angle_per_item
-        #    self._draw_text_angled(ctx, item.label(), rot, 1 - abs(rot))
-
-    def _draw_text_angled(
-        self, ctx: Ctx, text: str, angle: float, activity: float
-    ) -> None:
-        size = lerp(20, 40, activity)
-        color = lerp(0, 1, activity)
-        if color < 0.01:
-            return
-
-        ctx.save()
-        ctx.translate(-120, 0).rotate(angle).translate(140, 0)
-        ctx.font_size = size
-        ctx.rgba(1.0, 1.0, 1.0, color).move_to(0, 0).text(text)
-        ctx.restore()
-
-
-class SimpleMenu(MenuController):
-    """
-    A simple line-by-line menu.
-    """
-
-    def draw(self, ctx: Ctx) -> None:
-        ctx.gray(0)
-        ctx.rectangle(-120, -120, 240, 240).fill()
-
-        ctx.text_align = ctx.CENTER
-        ctx.text_baseline = ctx.MIDDLE
-
-        current = self._scroll_controller.current_position()
-
-        ctx.gray(1)
-        for ix, item in enumerate(self._items):
-            offs = (ix - current) * 30
-            size = lerp(30, 20, abs(offs / 20))
-            ctx.font_size = size
-            ctx.move_to(0, offs).text(item.label())
-
-
 menu_music = SimpleMenu(
     [
         MenuItemBack(),
diff --git a/python_payload/main_st4m.py b/python_payload/main_st4m.py
index 4e2bd30ed4d34a9002a544553e0d60a4e64ccce7..04aa335d21a94119dc3be8e240c2875c2417f583 100644
--- a/python_payload/main_st4m.py
+++ b/python_payload/main_st4m.py
@@ -22,17 +22,30 @@ from st4m import Responder, InputState, Ctx
 
 import math, hardware
 
+from st4m.ui.elements.menus import SunMenu, SimpleMenu
 
 vm = ViewManager(ViewTransitionBlend())
 
+menu_music = SimpleMenu(
+    [
+        MenuItemBack(),
+        MenuItemNoop("Harmonic"),
+        MenuItemNoop("Melodic"),
+        MenuItemNoop("TinySynth"),
+        MenuItemNoop("CrazySynth"),
+        MenuItemNoop("Sequencer"),
+    ],
+    vm,
+)
 
-def lerp(a: float, b: float, v: float) -> float:
-    if v <= 0:
-        return a
-    if v >= 1.0:
-        return b
-    return a + (b - a) * v
-
+menu_apps = SimpleMenu(
+    [
+        MenuItemBack(),
+        MenuItemNoop("captouch"),
+        MenuItemNoop("worms"),
+    ],
+    vm,
+)
 
 class USBIcon(Responder):
     """
@@ -205,7 +218,7 @@ menu_apps = SimpleMenu(
     vm,
 )
 
-menu_main = MainMenu(
+menu_main = SunMenu(
     [
         MenuItemForeground("Music", menu_music),
         MenuItemForeground("Apps", menu_apps),
diff --git a/python_payload/st4m/color.py b/python_payload/st4m/color.py
new file mode 100644
index 0000000000000000000000000000000000000000..da2de633adcd69cebfbe51c3ccbe6ee31ce385e8
--- /dev/null
+++ b/python_payload/st4m/color.py
@@ -0,0 +1,9 @@
+# Define a few RGB (0.0 to 1.0) colors
+BLACK = (0, 0, 0)
+RED = (1, 0, 0)
+GREEN = (0, 1, 0)
+BLUE = (0, 0, 1)
+WHITE = (1, 1, 1)
+GREY = (0.5, 0.5, 0.5)
+GO_GREEN = (63 / 255, 255 / 255, 33 / 255)
+PUSH_RED = (251 / 255, 72 / 255, 196 / 255)
diff --git a/python_payload/st4m/ui/elements/__init__.py b/python_payload/st4m/ui/elements/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/python_payload/st4m/ui/elements/menus.py b/python_payload/st4m/ui/elements/menus.py
new file mode 100644
index 0000000000000000000000000000000000000000..f05a7e852b00abfc8524d698bf2c356090f09180
--- /dev/null
+++ b/python_payload/st4m/ui/elements/menus.py
@@ -0,0 +1,130 @@
+from st4m.goose import Optional, List, ABCBase, abstractmethod
+from st4m.ui.view import ViewManager
+from st4m.ui.elements.visuals import Sun, GroupRing, FlowerIcon
+from st4m.ui.menu import MenuController, MenuItem
+
+from st4m import Ctx, InputState
+
+from st4m.utils import lerp
+import math
+from st4m.vector import tau
+
+
+class SimpleMenu(MenuController):
+    """
+    A simple line-by-line menu.
+    """
+
+    def draw(self, ctx: Ctx) -> None:
+        ctx.gray(0)
+        ctx.rectangle(-120, -120, 240, 240).fill()
+
+        ctx.text_align = ctx.CENTER
+        ctx.text_baseline = ctx.MIDDLE
+
+        current = self._scroll_controller.current_position()
+
+        ctx.gray(1)
+        for ix, item in enumerate(self._items):
+            offs = (ix - current) * 30
+            size = lerp(30, 20, abs(offs / 20))
+            ctx.font_size = size
+            ctx.move_to(0, offs).text(item.label())
+
+
+class SunMenu(MenuController):
+    """
+    A circular menu with a rotating sun.
+    """
+
+    __slots__ = (
+        "_ts",
+        "_sun",
+    )
+
+    def __init__(self, items: List[MenuItem], vm: ViewManager) -> None:
+        self._ts = 0
+        self._sun = Sun()
+        super().__init__(items, vm)
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        super().think(ins, delta_ms)
+        self._sun.think(ins, delta_ms)
+        self._ts += delta_ms
+
+    def _draw_text_angled(
+        self, ctx: Ctx, text: str, angle: float, activity: float
+    ) -> None:
+        size = lerp(20, 40, activity)
+        color = lerp(0, 1, activity)
+        if color < 0.01:
+            return
+
+        ctx.save()
+        ctx.translate(-120, 0).rotate(angle).translate(140, 0)
+        ctx.font_size = size
+        ctx.rgba(1.0, 1.0, 1.0, color).move_to(0, 0).text(text)
+        ctx.restore()
+
+    def draw(self, ctx: Ctx) -> None:
+        ctx.gray(0)
+        ctx.rectangle(-120, -120, 240, 240).fill()
+
+        self._sun.draw(ctx)
+
+        ctx.font_size = 40
+        ctx.text_align = ctx.CENTER
+        ctx.text_baseline = ctx.MIDDLE
+
+        angle_per_item = 0.4
+
+        current = self._scroll_controller.current_position()
+
+        for ix, item in enumerate(self._items):
+            rot = (ix - current) * angle_per_item
+            self._draw_text_angled(ctx, item.label(), rot, 1 - abs(rot))
+
+
+class FlowerMenu(MenuController):
+    """
+    A circular menu with flowers.
+    """
+
+    __slots__ = (
+        "_ts",
+        "_sun",
+    )
+
+    def __init__(self, items: List[MenuItem], vm: ViewManager, name="flow3r") -> None:
+        self._ts = 0
+        self.name = name
+        self.ui = GroupRing(r=80)
+        for item in items:
+            self.ui.items_ring.append(FlowerIcon(label=item.label()))
+        super().__init__(items, vm)
+        self._scroll_controller.wrap = True
+
+        self.icon = FlowerIcon(label=self.name)
+        self.icon.rotation_time = -5000
+        self.ui.item_center = self.icon
+
+        self.angle = 0
+        self.angle_step = 0.2
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        super().think(ins, delta_ms)
+        self.ui.think(ins, delta_ms)
+        self._ts += delta_ms
+
+    def draw(self, ctx: Ctx) -> None:
+        ctx.gray(0)
+        ctx.rectangle(-120, -120, 240, 240).fill()
+        for item in self.ui.items_ring:
+            item.highlighted = False
+            item.rotation_time = 10000
+        current = self._scroll_controller.current_position()
+        self.ui.items_ring[int(current)].highlighted = True
+        self.ui.items_ring[int(current)].rotation_time = 3000
+        self.ui.angle_offset = math.pi - (tau * current / len(self.ui.items_ring))
+
+        self.ui.draw(ctx)
diff --git a/python_payload/st4m/ui/elements/visuals.py b/python_payload/st4m/ui/elements/visuals.py
new file mode 100644
index 0000000000000000000000000000000000000000..244ae3036fdef667b65cd4cd0e5e04a2ec847b6d
--- /dev/null
+++ b/python_payload/st4m/ui/elements/visuals.py
@@ -0,0 +1,178 @@
+from st4m.utils import xy_from_polar
+from st4m.color import PUSH_RED, GO_GREEN, BLACK
+from st4m import Responder, Ctx, InputState
+
+
+import random
+import math
+from st4m.vector import tau
+
+
+class Sun(Responder):
+    """
+    A rotating sun widget.
+    """
+
+    def __init__(self) -> None:
+        self.x = 0.0
+        self.y = 0.0
+        self.size = 50.0
+        self.ts = 1.0
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        self.ts += delta_ms
+        pass
+
+    def draw(self, ctx: Ctx) -> None:
+        nrays = 10
+        angle_per_ray = 6.28 / nrays
+        for i in range(nrays):
+            angle = i * angle_per_ray + self.ts / 4000
+            angle %= 3.14159 * 2
+
+            if angle > 2 and angle < 4:
+                continue
+
+            ctx.save()
+            ctx.rgb(0.5, 0.5, 0)
+            ctx.line_width = 30
+            ctx.translate(-120, 0).rotate(angle)
+            ctx.move_to(20, 0)
+            ctx.line_to(260, 0)
+            ctx.stroke()
+            ctx.restore()
+
+        ctx.save()
+        ctx.rgb(0.92, 0.89, 0)
+        ctx.translate(-120, 0)
+
+        ctx.arc(self.x, self.y, self.size, 0, 6.29, 0)
+        ctx.fill()
+        ctx.restore()
+
+
+class GroupRing(Responder):
+    def __init__(self, r=100, x=0, y=0):
+        self.r = r
+        self.x = x
+        self.y = y
+        self.items_ring = []
+        self.item_center = None
+        self.angle_offset = 0
+        self.ts = 0.0
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        self.ts += delta_ms
+        self.item_center.think(ins, delta_ms)
+        for item in self.items_ring:
+            item.think(ins, delta_ms)
+
+    def draw(self, ctx: Ctx) -> None:
+        if self.item_center:
+            self.item_center.has_highlight = False
+            self.item_center.draw(ctx)
+            # self.items_ring[0].draw(ctx)
+
+        # ctx.save()
+        for index, item in enumerate(self.items_ring):
+            if item is None:
+                continue
+            angle = tau / len(self.items_ring) * index + self.angle_offset
+            (x, y) = xy_from_polar(self.r, angle)
+            ctx.save()
+            # ctx.translate(self.x + x, self.y + y)
+            ctx.rotate(-angle).translate(0, self.r).rotate(math.pi)
+            item.draw(ctx)
+            ctx.restore()
+        # ctx.restore()
+
+
+class FlowerIcon(Responder):
+    """
+    A flower icon
+    """
+
+    def __init__(self, label="?") -> None:
+        self.x = 0.0
+        self.y = 0.0
+        self.size = 50.0
+        self.ts = 1.0
+        self.bg = (random.random(), random.random(), random.random())
+        self.label = label
+
+        self.highlighted = False
+        self.rotation_time = 0.0
+
+        self.petal_count = random.randint(2, 3)
+        self.petal_color = (random.random(), random.random(), random.random())
+        self.phi_offset = random.random()
+        self.size_offset = random.randint(0, 20)
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        self.ts += delta_ms
+        pass
+
+    def draw(self, ctx: Ctx) -> None:
+        x = self.x
+        y = self.y
+        petal_size = 0
+        if self.petal_count:
+            petal_size = 2.3 * self.size / self.petal_count + self.size_offset
+
+        hs = 5
+        # print(self.ts)
+        ctx.save()
+        ctx.move_to(x, y)
+        ctx.text_align = ctx.CENTER
+        ctx.text_baseline = ctx.MIDDLE
+        ctx.font_size = self.size / 3
+        ctx.line_width = 5
+        if self.rotation_time:
+            phi_rotate = tau * ((self.ts % self.rotation_time) / self.rotation_time)
+        else:
+            phi_rotate = 0
+        for i in range(self.petal_count):
+            # ctx.save()
+
+            phi = (tau / self.petal_count * i + self.phi_offset + phi_rotate) % tau
+            r = self.size / 2
+            (x_, y_) = xy_from_polar(r, phi)
+
+            size_offset = abs(math.pi - (phi + math.pi) % tau) * 5
+            ctx.move_to(x + x_, y + y_)
+            if self.highlighted:
+                # ctx.move_to(x + x_ - petal_size / 2 - size_offset - 5, y + y_)
+                ctx.arc(x + x_, y + y_, petal_size / 2 + size_offset + 1, 0, tau, 0)
+                ctx.rgb(*GO_GREEN).stroke()
+
+            ctx.arc(x + x_, y + y_, petal_size / 2 + size_offset, 0, tau, 0)
+            ctx.rgb(*self.petal_color).fill()
+            # ctx.restore()
+        ctx.move_to(x, y)
+        if self.highlighted:
+            ctx.arc(x, y, self.size / 2, 0, tau, 1)
+            ctx.rgb(*GO_GREEN).stroke()
+
+        ctx.arc(x, y, self.size / 2, 0, tau, 0)
+        ctx.rgb(*self.bg).fill()
+
+        # label
+        # y += self.size / 3
+        w = max(self.size, ctx.text_width(self.label) + 10)
+        h = self.size / 3 + 8
+        if False and self.highlighted:
+            ctx.rgb(*BLACK).move_to(x, y - height / 2).round_rectangle(
+                x - width / 2, y - height / 2, width, height, width // 2
+            ).fill()
+            ctx.rgb(*GO_GREEN).move_to(x, y).text(self.label)
+        else:
+            ctx.save()
+            ctx.translate(0, self.size / 3)
+            ctx.rgb(*PUSH_RED).round_rectangle(
+                x - w / 2, y - h / 2, w, h, w // 2
+            ).fill()
+
+            ctx.rgb(*BLACK).move_to(x, y).text(self.label)
+            ctx.restore()
+
+        ctx.restore()
diff --git a/python_payload/st4m/utils.py b/python_payload/st4m/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..0123d7f7566409e46bd283f2edfddc2cd0a5f226
--- /dev/null
+++ b/python_payload/st4m/utils.py
@@ -0,0 +1,13 @@
+import math
+
+
+def lerp(a: float, b: float, v: float) -> float:
+    if v <= 0:
+        return a
+    if v >= 1.0:
+        return b
+    return a + (b - a) * v
+
+
+def xy_from_polar(r, phi):
+    return (r * math.sin(phi), r * math.cos(phi))  # x  # y