diff --git a/python_payload/apps/demo_worms4.py b/python_payload/apps/demo_worms4.py
new file mode 100644
index 0000000000000000000000000000000000000000..dfba5f02059185145b6597c19d0c8dc4aaf491d7
--- /dev/null
+++ b/python_payload/apps/demo_worms4.py
@@ -0,0 +1,139 @@
+# python imports
+import random
+import time
+import math
+
+# flow3r imports
+from st3m import event, ui
+from st4m import application
+from st4m import Ctx, InputState
+
+
+tau = 2 * math.pi
+
+
+# Subclass Application
+class AppWorms(application.Application):
+    def __init__(self, name):
+        super().__init__(name)
+
+        # HACK: we work against double buffering by keeping note of how many
+        # times on_draw got called.
+        #
+        # We know there's two buffers, so if we render the same state twice in a
+        # row we'll be effectively able to keep a persistent framebuffer, like
+        # with the old API.
+        #
+        # When bufn is in [0, 1] we render the background image.
+        # When bufn is in [2, ...) we render the worms.
+        # When bufn is > 3, we enable updating the worm state.
+        #
+        # TODO(q3k): allow apps to request single-buffered graphics for
+        # persistent framebuffers.
+        self.bufn = 0
+
+        self.worms = []
+        for i in range(0):
+            self.worms.append(Worm())
+
+        self.just_shown = True
+
+    def on_enter(self):
+        # print("on foreground")
+        self.just_shown = True
+
+    def draw(self, ctx):
+        if self.bufn == 0 or self.bufn == 1:
+            ctx.rgb(*ui.BLUE).rectangle(
+                -ui.WIDTH / 2, -ui.HEIGHT / 2, ui.WIDTH, ui.HEIGHT
+            ).fill()
+            ctx.text_align = ctx.CENTER
+            ctx.text_baseline = ctx.MIDDLE
+            ctx.move_to(0, 0).rgb(*ui.WHITE).text("touch me :)")
+            self.bufn += 1
+
+            return
+
+        for w in self.worms:
+            w.draw(ctx)
+        self.bufn += 1
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        super().think(ins, delta_ms)
+
+        # Simulation is currently locked to FPS.
+        if self.bufn > 3:
+            for w in self.worms:
+                w.move()
+            self.bufn = 2
+        for index, petal in enumerate(self.input.captouch.petals):
+            if petal.pressed or petal.repeated:
+                self.worms.append(Worm(tau * index / 10 + math.pi))
+
+    def handle_input(self, data):
+        worms = self.worms
+        worms.append(Worm(data.get("index", 0) * 2 * math.pi / 10 + math.pi))
+        if len(worms) > 10:
+            worms.pop(0)
+
+
+class Worm:
+    def __init__(self, direction=None):
+        self.color = ui.randrgb()
+
+        if direction:
+            self.direction = direction
+        else:
+            self.direction = random.random() * math.pi * 2
+
+        self.size = 50
+        self.speed = self.size / 5
+        (x, y) = ui.xy_from_polar(100, self.direction)
+        self.x = x
+        self.y = y
+        # (self.dx,self.dy) = xy_from_polar(1,self.direction)
+        self._lastdist = 0.0
+
+    def draw(self, ctx):
+        ctx.rgb(*self.color)
+        ctx.round_rectangle(
+            self.x - self.size / 2,
+            self.y - self.size / 2,
+            self.size,
+            self.size,
+            self.size // 2,
+        ).fill()
+
+    def mutate(self):
+        self.color = [
+            max(0, min(1, x + ((random.random() - 0.5) * 0.3))) for x in self.color
+        ]
+
+    def move(self):
+        dist = math.sqrt(self.x**2 + self.y**2)
+        target_size = (130 - dist) / 3
+
+        if self.size > target_size:
+            self.size -= 1
+
+        if self.size < target_size:
+            self.size += 1
+
+        self.speed = self.size / 5
+
+        self.direction += (random.random() - 0.5) * math.pi / 4
+
+        (dx, dy) = ui.xy_from_polar(self.speed, self.direction)
+        self.x += dx
+        self.y += dy
+
+        if dist > 120 - self.size / 2 and dist > self._lastdist:
+            polar_position = math.atan2(self.y, self.x)
+            dx = dx * -abs(math.cos(polar_position))
+            dy = dy * -abs(math.sin(polar_position))
+            self.direction = -math.atan2(dy, dx)
+            self.mutate()
+        self._lastdist = dist
+
+
+app = AppWorms("worms")
diff --git a/python_payload/main.py b/python_payload/main.py
index 16867279cb732621f936554a8260e47ead0a1c3d..fbbd8df4c814ce08dbecc74f00ce1fe17ae8da5c 100644
--- a/python_payload/main.py
+++ b/python_payload/main.py
@@ -46,11 +46,14 @@ menu_music = SimpleMenu(
     vm,
 )
 
+from apps.demo_worms4 import app as worms
+
+worms._view_manager = vm
 menu_apps = SimpleMenu(
     [
         MenuItemBack(),
         MenuItemNoop("captouch"),
-        MenuItemNoop("worms"),
+        MenuItemForeground("worms", worms),
     ],
     vm,
 )
@@ -58,7 +61,7 @@ menu_apps = SimpleMenu(
 
 menu_main = FlowerMenu(
     [
-        MenuItemForeground("MUsic", menu_music),
+        MenuItemForeground("Music", menu_music),
         MenuItemForeground("Apps", menu_apps),
         MenuItemNoop("Settings"),
     ],
diff --git a/python_payload/st4m/application.py b/python_payload/st4m/application.py
new file mode 100644
index 0000000000000000000000000000000000000000..dcb44fcadfb13036113c545a558718e5684c972b
--- /dev/null
+++ b/python_payload/st4m/application.py
@@ -0,0 +1,15 @@
+from st4m.ui.view import ViewWithInputState, ViewTransitionSwipeRight
+
+
+class Application(ViewWithInputState):
+    def __init__(self, name: str = __name__):
+        self._name = name
+        self._view_manager = None
+        super().__init__()
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        super().think(ins, delta_ms)
+
+        if self.input.left_shoulder.middle.pressed:
+            if self._view_manager is not None:
+                self._view_manager.pop(ViewTransitionSwipeRight())
diff --git a/python_payload/st4m/input.py b/python_payload/st4m/input.py
index 576bb906cbd084f911d5e46c1361169c05b51262..cdeacc05ba85e4e9efed3729426449ab96af8ecf 100644
--- a/python_payload/st4m/input.py
+++ b/python_payload/st4m/input.py
@@ -8,24 +8,24 @@ class InputState:
     """
     Current state of inputs from badge user. Passed via think() to every
     Responder.
-    
+
     If you want to detect edges, use the stateful InputController.
     """
-    def __init__(self, petal_pressed: List[bool], left_button: int, right_button: int) -> None:
+
+    def __init__(
+        self, petal_pressed: List[bool], left_button: int, right_button: int
+    ) -> None:
         self.petal_pressed = petal_pressed
         self.left_button = left_button
         self.right_button = right_button
-    
+
     @classmethod
-    def gather(cls) -> 'InputState':
+    def gather(cls) -> "InputState":
         """
         Build InputState from current hardware state. Should only be used by the
         Reactor.
         """
-        petal_pressed = [
-            hardware.get_captouch(i)
-            for i in range(10)
-        ]
+        petal_pressed = [hardware.get_captouch(i) for i in range(10)]
         left_button = hardware.left_button_get()
         right_button = hardware.right_button_get()
 
@@ -48,11 +48,11 @@ class Pressable:
     button repeating.
     """
 
-    PRESSED = 'pressed'
-    REPEATED = 'repeated'
-    RELEASED = 'released'
-    DOWN = 'down'
-    UP = 'up'
+    PRESSED = "pressed"
+    REPEATED = "repeated"
+    RELEASED = "released"
+    DOWN = "down"
+    UP = "up"
 
     def __init__(self, state: bool) -> None:
         self._state = state
@@ -93,7 +93,6 @@ class Pressable:
                     self._prev_state = False
                     self._pressed_at = ts
                     self._repeated = True
-        
 
     @property
     def state(self) -> str:
@@ -162,10 +161,10 @@ class Pressable:
         self._ignoring = 2
         self._repeating = False
         self._repeated = False
-    
+
     def __repr__(self) -> str:
-        return '<Pressable: ' + self.state + '>'
-    
+        return "<Pressable: " + self.state + ">"
+
 
 class PetalState(Pressable):
     def __init__(self, ix: int) -> None:
@@ -180,18 +179,16 @@ class CaptouchState:
     The petals are indexed from 0 to 9 (inclusive). Petal 0 is above the USB-C
     socket, then the numbering continues counter-clockwise.
     """
-    __slots__ = ('petals')
+
+    __slots__ = "petals"
 
     def __init__(self) -> None:
-        self.petals = [
-            PetalState(i)
-            for i in range(10)
-        ]
-    
+        self.petals = [PetalState(i) for i in range(10)]
+
     def _update(self, ts: int, hr: InputState) -> None:
         for i, petal in enumerate(self.petals):
             petal._update(ts, hr.petal_pressed[i])
-    
+
     def _ignore_pressed(self) -> None:
         for petal in self.petals:
             petal._ignore_pressed()
@@ -201,15 +198,17 @@ class TriSwitchHandedness(Enum):
     """
     Left or right shoulder button.
     """
-    left = 'left'
-    right = 'right'
+
+    left = "left"
+    right = "right"
 
 
 class TriSwitchState:
     """
     State of a tri-stat shoulder button
     """
-    __slots__ = ('left', 'middle', 'right', 'handedness')
+
+    __slots__ = ("left", "middle", "right", "handedness")
 
     def __init__(self, h: TriSwitchHandedness) -> None:
         self.handedness = h
@@ -219,7 +218,11 @@ class TriSwitchState:
         self.right = Pressable(False)
 
     def _update(self, ts: int, hr: InputState) -> None:
-        st = hr.left_button if self.handedness == TriSwitchHandedness.left else hr.right_button
+        st = (
+            hr.left_button
+            if self.handedness == TriSwitchHandedness.left
+            else hr.right_button
+        )
         self.left._update(ts, st == -1)
         self.middle._update(ts, st == 2)
         self.right._update(ts, st == 1)
@@ -228,7 +231,7 @@ class TriSwitchState:
         self.left._ignore_pressed()
         self.middle._ignore_pressed()
         self.right._ignore_pressed()
-    
+
 
 class InputController:
     """
@@ -241,12 +244,14 @@ class InputController:
 
     Then, access the captouch/left_shoulder/right_shoulder fields.
     """
+
     __slots__ = (
-        'captouch',
-        'left_shoulder',
-        'right_shoulder',
-        '_ts',
+        "captouch",
+        "left_shoulder",
+        "right_shoulder",
+        "_ts",
     )
+
     def __init__(self) -> None:
         self.captouch = CaptouchState()
         self.left_shoulder = TriSwitchState(TriSwitchHandedness.left)
@@ -268,4 +273,3 @@ class InputController:
         self.captouch._ignore_pressed()
         self.left_shoulder._ignore_pressed()
         self.right_shoulder._ignore_pressed()
-
diff --git a/python_payload/st4m/ui/elements/visuals.py b/python_payload/st4m/ui/elements/visuals.py
index 244ae3036fdef667b65cd4cd0e5e04a2ec847b6d..43236a4411a94076ba4b53100bdcb2f009f13cef 100644
--- a/python_payload/st4m/ui/elements/visuals.py
+++ b/python_payload/st4m/ui/elements/visuals.py
@@ -84,7 +84,6 @@ class GroupRing(Responder):
             ctx.rotate(-angle).translate(0, self.r).rotate(math.pi)
             item.draw(ctx)
             ctx.restore()
-        # ctx.restore()
 
 
 class FlowerIcon(Responder):
@@ -103,7 +102,7 @@ class FlowerIcon(Responder):
         self.highlighted = False
         self.rotation_time = 0.0
 
-        self.petal_count = random.randint(2, 3)
+        self.petal_count = random.randint(3, 5)
         self.petal_color = (random.random(), random.random(), random.random())
         self.phi_offset = random.random()
         self.size_offset = random.randint(0, 20)
@@ -127,11 +126,13 @@ class FlowerIcon(Responder):
         ctx.text_baseline = ctx.MIDDLE
         ctx.font_size = self.size / 3
         ctx.line_width = 5
+        ctx.font = ctx.get_font_name(6)
         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):
+            # continue
             # ctx.save()
 
             phi = (tau / self.petal_count * i + self.phi_offset + phi_rotate) % tau
@@ -158,21 +159,20 @@ class FlowerIcon(Responder):
 
         # 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)
+        # ctx.save()
+        ctx.translate(0, self.size / 3)
+
+        if self.highlighted:
+            bg = BLACK
+            fg = GO_GREEN
         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()
+            bg = PUSH_RED
+            fg = BLACK
 
-            ctx.rgb(*BLACK).move_to(x, y).text(self.label)
-            ctx.restore()
+        ctx.rgb(*bg).round_rectangle(x - w / 2, y - h / 2, w, h, w // 2).fill()
+        ctx.rgb(*fg).move_to(x, y).text(self.label)
 
         ctx.restore()
diff --git a/python_payload/st4m/ui/view.py b/python_payload/st4m/ui/view.py
index a66d9194f357d2854ae3333791ac216e2477dbfe..da1948874465ab3cded8816ebe7f9582b0cd50d6 100644
--- a/python_payload/st4m/ui/view.py
+++ b/python_payload/st4m/ui/view.py
@@ -30,9 +30,8 @@ class ViewWithInputState(View):
 
     Remember to call super().think() in think()!
     """
-    __slots__ = (
-        'input',
-    )
+
+    __slots__ = ("input",)
 
     def __init__(self) -> None:
         self.input = InputController()
@@ -50,8 +49,11 @@ class ViewTransition(ABCBase):
 
     Can be implemented by the user to provide transition animations.
     """
+
     @abstractmethod
-    def draw(self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder) -> None:
+    def draw(
+        self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
+    ) -> None:
         """
         Called when the ViewManager performs a transition from the outgoing
         responder to the incoming responder. The implementer should draw both
@@ -67,7 +69,10 @@ class ViewTransitionBlend(ViewTransition):
     """
     Transition from one view to another by opacity blending.
     """
-    def draw(self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder) -> None:
+
+    def draw(
+        self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
+    ) -> None:
         ctx.start_group()
         outgoing.draw(ctx)
         ctx.end_group()
@@ -82,7 +87,10 @@ class ViewTransitionSwipeLeft(ViewTransition):
     """
     Swipe the outoing view to the left and replace it with the incoming view.
     """
-    def draw(self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder) -> None:
+
+    def draw(
+        self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
+    ) -> None:
         ctx.save()
         ctx.translate(transition * -240, 0)
         outgoing.draw(ctx)
@@ -98,7 +106,10 @@ class ViewTransitionSwipeRight(ViewTransition):
     """
     Swipe the outoing view to the right and replace it with the incoming view.
     """
-    def draw(self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder) -> None:
+
+    def draw(
+        self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
+    ) -> None:
         ctx.save()
         ctx.translate(transition * 240, 0)
         outgoing.draw(ctx)
@@ -117,6 +128,7 @@ class ViewManager(Responder):
     It manages a history of Views, to which new Views can be pushed and then
     popped.
     """
+
     def __init__(self, vt: ViewTransition) -> None:
         """
         Create a new ViewManager with a default ViewTransition.
@@ -124,7 +136,7 @@ class ViewManager(Responder):
         self._incoming: Optional[View] = None
         self._outgoing: Optional[View] = None
 
-		# Transition time.
+        # Transition time.
         self._time_ms = 150
 
         self._default_vt = vt
@@ -140,9 +152,9 @@ class ViewManager(Responder):
             if self._transition >= 1.0:
                 self._transition = 0
                 self._transitioning = False
-                
+
                 self._outgoing = None
-        
+
         if self._outgoing is not None:
             self._outgoing.think(ins, delta_ms)
         if self._incoming is not None:
@@ -195,4 +207,4 @@ class ViewManager(Responder):
         animation.
         """
         r = self._history.pop()
-        self.replace(r, override_vt)
\ No newline at end of file
+        self.replace(r, override_vt)