diff --git a/src/crab/common/frontend/controller.cr b/src/crab/common/frontend/controller.cr
index 9f4b779..a8e9c15 100644
--- a/src/crab/common/frontend/controller.cr
+++ b/src/crab/common/frontend/controller.cr
@@ -1,8 +1,14 @@
 abstract class Controller
+  alias Action = Tuple(String, Proc(Nil), Bool)
+
   abstract def emu : Emu
 
   abstract def width : Int32
   abstract def height : Int32
+  abstract def name : String
+  abstract def actions(& : Action ->)
+
+  getter actions = [] of Action
 
   def window_width : Int32
     width
diff --git a/src/crab/common/frontend/controllers/gb_controller.cr b/src/crab/common/frontend/controllers/gb_controller.cr
index 8149cba..af80699 100644
--- a/src/crab/common/frontend/controllers/gb_controller.cr
+++ b/src/crab/common/frontend/controllers/gb_controller.cr
@@ -6,8 +6,14 @@ class GBController < Controller
   getter width : Int32 = 160
   getter height : Int32 = 144
 
+  getter name : String = "Game Boy (Color)"
+
   def initialize(bios : String?, rom : String)
     @emu = GB::GB.new(bios, rom, true, false)
     @emu.post_init
   end
+
+  def actions(& : Action ->)
+    yield Action.new("Sync", ->@emu.toggle_sync, emu.apu.sync)
+  end
 end
diff --git a/src/crab/common/frontend/controllers/gba_controller.cr b/src/crab/common/frontend/controllers/gba_controller.cr
index f38ef75..52de602 100644
--- a/src/crab/common/frontend/controllers/gba_controller.cr
+++ b/src/crab/common/frontend/controllers/gba_controller.cr
@@ -6,8 +6,14 @@ class GBAController < Controller
   getter width : Int32 = 240
   getter height : Int32 = 160
 
+  getter name : String = "Game Boy Advance"
+
   def initialize(bios : String?, rom : String)
     @emu = GBA::GBA.new(gba_bios, rom)
     @emu.post_init
   end
+
+  def actions(& : Action ->)
+    yield Action.new("Sync", ->@emu.toggle_sync, emu.apu.sync)
+  end
 end
diff --git a/src/crab/common/frontend/controllers/stubbed_controller.cr b/src/crab/common/frontend/controllers/stubbed_controller.cr
index c7ba27c..dc07b93 100644
--- a/src/crab/common/frontend/controllers/stubbed_controller.cr
+++ b/src/crab/common/frontend/controllers/stubbed_controller.cr
@@ -5,6 +5,8 @@ class StubbedController < Controller
   getter window_height : Int32 = 160
   class_getter extensions = [] of String
 
+  getter name : String = ""
+
   def emu : Emu
     abort "Called emu method in StubbedController"
   end
@@ -24,4 +26,7 @@ class StubbedController < Controller
 
   def toggle_sync : Nil
   end
+
+  def actions(& : Action ->)
+  end
 end
diff --git a/src/crab/common/frontend/sdl_opengl_imgui_frontend.cr b/src/crab/common/frontend/sdl_opengl_imgui_frontend.cr
index 65dd078..23ac801 100644
--- a/src/crab/common/frontend/sdl_opengl_imgui_frontend.cr
+++ b/src/crab/common/frontend/sdl_opengl_imgui_frontend.cr
@@ -2,9 +2,10 @@ require "./controllers/*"
 require "./widgets/*"
 
 class SDLOpenGLImGuiFrontend < Frontend
-  CONTROLLERS = [StubbedController, GBController, GBAController]
-  SCALE       = 4
-  SHADERS     = "src/crab/common/shaders"
+  CONTROLLERS    = [StubbedController, GBController, GBAController]
+  ROM_EXTENSIONS = CONTROLLERS.reduce([] of String) { |acc, controller| acc + controller.extensions }
+  SCALE          = 4
+  SHADERS        = "src/crab/common/shaders"
 
   @controller : Controller
 
@@ -42,7 +43,7 @@ class SDLOpenGLImGuiFrontend < Frontend
     @opengl_info = OpenGLInfo.new
     @io = setup_imgui
 
-    @file_explorer = ImGui::FileExplorer.new(CONTROLLERS.reduce([] of String) { |acc, controller| acc + controller.extensions })
+    @file_explorer = ImGui::FileExplorer.new(ROM_EXTENSIONS)
 
     @open_first_frame = @controller.class == StubbedController
     LibSDL.gl_set_swap_interval(1) if @open_first_frame
@@ -89,9 +90,9 @@ class SDLOpenGLImGuiFrontend < Frontend
       when SDL::Event::Keyboard
         case event.sym
         when .tab? then @controller.toggle_sync if event.pressed?
-        # when .m?   then toggle_blending if event.pressed?
-        when .q?   then exit 0
-        else            @controller.handle_event(event)
+          # when .m?   then toggle_blending if event.pressed?
+        when .q? then exit 0
+        else          @controller.handle_event(event)
         end
       else nil
       end
@@ -141,13 +142,20 @@ class SDLOpenGLImGuiFrontend < Frontend
           ImGui.menu_item "Overlay", "", pointerof(@enable_overlay)
           # ImGui.menu_item "Blend", "", pointerof(@enable_blend) todo: re-implement blending now that frames are cleared
           ImGui.menu_item "Pause", "", pointerof(@pause)
-          ImGui.menu_item "Sync", "", pointerof(@sync)
           ImGui.end_menu
 
           toggle_blending if @enable_blend ^ @blending
           LibSDL.gl_set_swap_interval(@pause.to_unsafe) if previously_paused ^ @pause
-          @controller.toggle_sync if previously_synced ^ @sync
         end
+
+        name = @controller.name
+        if name.size > 0 && ImGui.begin_menu name
+          @controller.actions do |name, callback, enabled|
+            callback.call if ImGui.menu_item(name, "", enabled)
+          end
+          ImGui.end_menu
+        end
+
         overlay_height += ImGui.get_window_size.y
         ImGui.end_main_menu_bar
       end
diff --git a/src/crab/gb/apu.cr b/src/crab/gb/apu.cr
index ede83a6..4b70d8b 100644
--- a/src/crab/gb/apu.cr
+++ b/src/crab/gb/apu.cr
@@ -29,7 +29,7 @@ module GB
     @audiospec : LibSDL::AudioSpec
     @obtained_spec : LibSDL::AudioSpec
 
-    @sync : Bool
+    getter sync : Bool
 
     def initialize(@gb : GB, headless : Bool)
       @sync = !headless
diff --git a/src/crab/gba/apu.cr b/src/crab/gba/apu.cr
index f22fd4a..0ebaa26 100644
--- a/src/crab/gba/apu.cr
+++ b/src/crab/gba/apu.cr
@@ -24,7 +24,7 @@ module GBA
     @audiospec : LibSDL::AudioSpec
     @obtained_spec : LibSDL::AudioSpec
 
-    @sync : Bool = true
+    getter sync : Bool = true
 
     def initialize(@gba : GBA)
       @audiospec = LibSDL::AudioSpec.new