diff --git a/ad7147/src/driver.rs b/ad7147/src/driver.rs
index 32784287d49733023b922fbbf6e1173d53f4de69..164d5adf587b053f329d0703d13e6f05d627ebe4 100644
--- a/ad7147/src/driver.rs
+++ b/ad7147/src/driver.rs
@@ -53,13 +53,13 @@ where
             let data_idx = (i * 8) + 1;
             data[data_idx..data_idx + 8].copy_from_slice(&stage.to_reg_value());
         }
-        println!("writing to device: addr: {:016b} stage0: {:016b}, stage0: {:016b}", data[0], data[1], data[2]);
+        //println!("writing to device: addr: {:016b} stage0: {:016b}, stage0: {:016b}", data[0], data[1], data[2]);
         self.i2c.write(self.address, to_be_array(data).as_byte_slice())?;
 
         let mut data = [0u16; 9];
         data[0] = 0x000;
         data[1..9].copy_from_slice(&configuration.0.to_reg_value_for_init());
-        println!("writing to device: addr: {:016b} pwr_cfg: {:016b}, stage_cal: {:016b}, amb_comp_1: {:016b}, amb_comp_2: {:016b}, amb_comp_3: {:016b}, stage_low_int: {:016b}, stage_high_int: {:016b}, stage_complete_int: {:016b}", data[0], data[1], data[2], data[3], data[4], data[5],  data[6], data[7], data[8]);
+        //println!("writing to device: addr: {:016b} pwr_cfg: {:016b}, stage_cal: {:016b}, amb_comp_1: {:016b}, amb_comp_2: {:016b}, amb_comp_3: {:016b}, stage_low_int: {:016b}, stage_high_int: {:016b}, stage_complete_int: {:016b}", data[0], data[1], data[2], data[3], data[4], data[5],  data[6], data[7], data[8]);
         self.i2c.write(self.address, to_be_array(data).as_byte_slice())?;
 
         delay.delay_ms(100);
@@ -67,7 +67,7 @@ where
         let mut data = [0u16; 2];
         data[0] = CalibrationEnable::REGISTER;
         data[1] = configuration.0.calibration_enable.to_reg_value();
-        println!("writing to device: addr: {:016b} stage_cal: {:016b}", data[0], data[1]);
+        //println!("writing to device: addr: {:016b} stage_cal: {:016b}", data[0], data[1]);
         self.i2c.write(self.address, to_be_array(data).as_byte_slice())?;
 
         Ok(Ad7147 {
@@ -87,7 +87,7 @@ where
         let mut result = [0u8; 12*2];
         self.i2c
             .write_read(self.address, to_be_array([STAGE_CONVERSION_RESULT_REGISTER]).as_byte_slice(), &mut result)?;
-        println!("read from device {:x?}", result);
+        //println!("read from device {:x?}", result);
         Ok(to_le_u16_array(&result))
     }
 
@@ -95,7 +95,7 @@ where
         let mut data = [0u8; 6];
         self.i2c
             .write_read(self.address, to_be_array([STAGE_COMPLETED_INTERRUPT_RESULT_REGISTER]).as_byte_slice(), &mut data)?;
-        println!("read from device {:x?}", data);
+        //println!("read from device {:x?}", data);
         Ok(InterruptStatus::from_registers(to_le_u16_array(&data)))
     }
 
diff --git a/src/demo_tasks.rs b/src/demo_tasks.rs
index 329cb1a70ade964de2295bfbbb6d097deebcc43a..b0feda9d18230d726644422f6394e408df5749a9 100644
--- a/src/demo_tasks.rs
+++ b/src/demo_tasks.rs
@@ -1,12 +1,13 @@
-use crate::flow3r::display::Display;
-use embassy_futures::select::{select, Either};
+use crate::flow3r::{display::Display, imu::ImuHandler};
+use bmi270::AxisData;
+use embassy_futures::select::{select, Either, select3, Either3};
 use embassy_time::{Duration, Timer};
 use embedded_graphics::{
     image::Image,
     mono_font::{ascii::FONT_6X10, MonoTextStyle},
     pixelcolor::Rgb565,
     prelude::*,
-    primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
+    primitives::{Circle, PrimitiveStyle, Rectangle, StyledDrawable},
     text::Text,
 };
 use esp_backtrace as _;
@@ -33,12 +34,10 @@ pub async fn leds_fade(mut leds: crate::flow3r::leds::Leds) -> ! {
     }
 }
 
-#[embassy_executor::task]
-pub async fn display_demo(mut display: crate::flow3r::display::Display) -> ! {
+pub async fn display_demo(display: &mut crate::flow3r::display::Display) {
     let input = InputHandler;
     let mut inputs = input.split();
 
-    println!("running display demo");
     display.set_backlight(100).unwrap();
 
     let mut rect = Rectangle::with_center(Point { x: 120, y: 120 }, Size::new(50, 50));
@@ -52,23 +51,21 @@ pub async fn display_demo(mut display: crate::flow3r::display::Display) -> ! {
     display
         .fill_solid(&display.bounding_box(), Rgb565::BLACK)
         .unwrap();
-    text.draw(&mut display).unwrap();
-    rect.draw_styled(&rect_style, &mut display).unwrap();
+    text.draw(display).unwrap();
+    rect.draw_styled(&rect_style, display).unwrap();
     display.flush().await.unwrap();
 
     loop {
-        match select(
+        match select3(
             inputs.sw1_left.wait_for_press(),
             inputs.sw1_right.wait_for_press(),
+            inputs.sw2_center.wait_for_press(),
         )
         .await
         {
-            Either::First(_) => {
-                move_rectangle(&mut rect, &text, &mut display, &rect_style, -5).await
-            }
-            Either::Second(_) => {
-                move_rectangle(&mut rect, &text, &mut display, &rect_style, 5).await
-            }
+            Either3::First(_) => move_rectangle(&mut rect, &text, display, &rect_style, -5).await,
+            Either3::Second(_) => move_rectangle(&mut rect, &text, display, &rect_style, 5).await,
+            Either3::Third(_) => break
         }
     }
 }
@@ -111,3 +108,44 @@ pub async fn draw_start_screen(display: &mut Display) {
     display.flush().await.unwrap();
     display.set_backlight(100).unwrap();
 }
+
+pub async fn imu_demo(display: &mut Display /*imu: &mut ImuHandler*/) {
+    let input = InputHandler;
+    let mut inputs = input.split();
+
+    let circle = Circle::with_center(display.bounding_box().center(), 20);
+    let circle_style = PrimitiveStyle::with_fill(Rgb565::YELLOW);
+
+    display
+        .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+        .unwrap();
+    circle.draw_styled(&circle_style, display).unwrap();
+    display.flush().await.unwrap();
+
+    let mut offset = (0i32, 0i32);
+    loop {
+        match select(inputs.sw2_center.wait_for_press(), async {
+            //let imu_value = imu.rotation().unwrap();
+            let imu_value = AxisData { x: 5, y: 5, z: 0 };
+            offset = (
+                (-80).max(80.min(offset.0 + imu_value.x as i32)),
+                (-80).max(80.min(offset.1 + imu_value.y as i32)),
+            );
+            display
+                .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+                .unwrap();
+            println!("offset: {}, {}", offset.0, offset.1);
+            circle
+                .translate(Point::new(offset.0, offset.1))
+                .draw_styled(&circle_style, display)
+                .unwrap();
+            display.flush().await.unwrap();
+            Timer::after(Duration::from_millis(20)).await;
+        })
+        .await
+        {
+            Either::First(_) => break,
+            Either::Second(_) => (),
+        }
+    }
+}
diff --git a/src/flow3r/captouch.rs b/src/flow3r/captouch.rs
index e6c724c77849137923b4aae75b2b1d579fed370b..08d97ef238853a466d6c60ca3e2520aed1cd535a 100644
--- a/src/flow3r/captouch.rs
+++ b/src/flow3r/captouch.rs
@@ -283,7 +283,7 @@ pub async fn captouch_controller(
         let _ = ad7147_top.read_interrupt_registers().unwrap();
         //println!("ints: {:?}", ints);
         let measurement = ad7147_bot.read_all_stages().unwrap();
-        println!(
+        /*println!(
             "{} {} {} {} {} {} {} {} {} {} {} {}",
             measurement[0],
             measurement[1],
@@ -297,9 +297,9 @@ pub async fn captouch_controller(
             measurement[9],
             measurement[10],
             measurement[11]
-        );
+        );*/
         let measurement = ad7147_top.read_all_stages().unwrap();
-        println!(
+        /*println!(
             "{} {} {} {} {} {} {} {} {} {} {} {}",
             measurement[0],
             measurement[1],
@@ -313,7 +313,7 @@ pub async fn captouch_controller(
             measurement[9],
             measurement[10],
             measurement[11]
-        );
+        );*/
         Timer::after(Duration::from_millis(1000)).await;
     }
 }
diff --git a/src/flow3r/mod.rs b/src/flow3r/mod.rs
index 6551c92f820776ad4f768543843040f26c6fbbcf..185d2bcb0b1d0b334daffe863e3df0c01d2ec324 100644
--- a/src/flow3r/mod.rs
+++ b/src/flow3r/mod.rs
@@ -12,12 +12,13 @@ pub mod imu;
 pub mod input;
 pub mod leds;
 pub mod sdcard;
+pub mod ui;
 
 pub struct Flow3r {
     pub badgelink: BadgeLink,
     pub captouch: CapTouchHandler,
     pub display: Display,
-    pub imu: ImuHandler,
+    //pub imu: ImuHandler,
     pub inputs: InputHandler,
     pub leds: Leds,
 }
@@ -27,7 +28,7 @@ impl Flow3r {
         badgelink: BadgeLink,
         captouch: CapTouchHandler,
         display: Display,
-        imu: ImuHandler,
+        //imu: ImuHandler,
         inputs: InputHandler,
         leds: Leds,
     ) -> Self {
@@ -35,7 +36,7 @@ impl Flow3r {
             badgelink,
             captouch,
             display,
-            imu,
+            //imu,
             inputs,
             leds,
         }
diff --git a/src/flow3r/ui/main_menu.rs b/src/flow3r/ui/main_menu.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9d68791cbf3b64aef3207841c51b455403d5fb50
--- /dev/null
+++ b/src/flow3r/ui/main_menu.rs
@@ -0,0 +1,114 @@
+use embassy_futures::select::{select3, Either3};
+use embassy_time::{Duration, Timer};
+use embedded_graphics::{
+    mono_font::{ascii::FONT_10X20, MonoTextStyle},
+    pixelcolor::Rgb565,
+    prelude::*,
+    text::Text,
+};
+use esp_println::println;
+
+use crate::{
+    demo_tasks::{display_demo, imu_demo},
+    flow3r::{display::Display, input::InputHandler},
+};
+
+pub async fn main_menu(mut display: Display, inputs: InputHandler) -> ! {
+    let mut inputs = inputs.split();
+
+    let apps = ["input_test", "imu_test", "captouch_test"];
+    let mut selected = 0usize;
+
+    display
+        .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+        .unwrap();
+    let mut text = Text::with_alignment(
+        apps[selected],
+        Point { x: 120, y: 120 },
+        MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE),
+        embedded_graphics::text::Alignment::Center,
+    );
+    text.draw(&mut display).unwrap();
+    display.flush().await.unwrap();
+
+    loop {
+        match select3(
+            inputs.sw1_center.wait_for_press(),
+            inputs.sw1_right.wait_for_press(),
+            inputs.sw1_left.wait_for_press(),
+        )
+        .await
+        {
+            Either3::First(_) => {
+                start_current_app(apps[selected], &mut display).await;
+                display
+                    .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+                    .unwrap();
+                text.draw(&mut display).unwrap();
+                display.flush().await.unwrap();
+            }
+            Either3::Second(_) => {
+                let selected_new = (apps.len() - 1).min(selected + 1);
+                if selected != selected_new {
+                    play_transition_animation(&mut display, apps[selected_new], &mut text, false)
+                        .await;
+                }
+                selected = selected_new;
+            }
+            Either3::Third(_) => {
+                let selected_new = if selected > 0 { selected - 1 } else { selected };
+                if selected != selected_new {
+                    play_transition_animation(&mut display, apps[selected_new], &mut text, true)
+                        .await;
+                }
+                selected = selected_new;
+            }
+        }
+    }
+}
+
+async fn play_transition_animation<'a>(
+    display: &mut Display,
+    app: &'a str,
+    text: &mut Text<'a, MonoTextStyle<'a, Rgb565>>,
+    direction: bool,
+) {
+    let mut offset = 0i32;
+
+    while offset < text.bounding_box().size.width as i32 / 2 + 120 {
+        offset += 20;
+        display
+            .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+            .unwrap();
+        text.translate(Point::new(if direction { offset } else { -offset }, 0))
+            .draw(display)
+            .unwrap();
+        display.flush().await.unwrap();
+        Timer::after(Duration::from_millis(1)).await;
+    }
+
+    text.text = app;
+
+    let mut offset = text.bounding_box().size.width as i32 / 2 + 120;
+
+    while offset > 0 {
+        offset -= 20;
+        display
+            .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+            .unwrap();
+        text.translate(Point::new(if direction { -offset } else { offset }, 0))
+            .draw(display)
+            .unwrap();
+        display.flush().await.unwrap();
+        Timer::after(Duration::from_millis(1)).await;
+    }
+}
+
+async fn start_current_app(app: &str, display: &mut Display) {
+    match app {
+        "input_test" => display_demo(display).await,
+        "imu_test" => imu_demo(display).await,
+        "captouch_test" => {}
+        _ => (),
+    }
+}
diff --git a/src/flow3r/ui/mod.rs b/src/flow3r/ui/mod.rs
index 8b137891791fe96927ad78e64b0aad7bded08bdc..515f306e4e6c6cce781cbc6b141e0b5e8d1dbe86 100644
--- a/src/flow3r/ui/mod.rs
+++ b/src/flow3r/ui/mod.rs
@@ -1 +1 @@
-
+pub mod main_menu;
diff --git a/src/main.rs b/src/main.rs
index 0f421682daa85208aeff0ce187638c68d0379a99..1dff389d14fb6b0a44c009e167b13224b8cab0af 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,7 +13,7 @@ use embassy_executor::Spawner;
 use embassy_time::{Duration, Timer};
 
 use esp_backtrace as _;
-use flow3r::Flow3r;
+use flow3r::{ui::main_menu::main_menu, Flow3r};
 use hal::prelude::*;
 
 use runtime::start_runtime;
@@ -26,13 +26,12 @@ fn runtime() -> ! {
 #[embassy_executor::task]
 async fn main(mut flow3r: Flow3r) -> ! {
     draw_start_screen(&mut flow3r.display).await;
-    Timer::after(Duration::from_secs(10)).await;
 
     let spawner = Spawner::for_current_executor().await;
     spawner.spawn(demo_tasks::leds_fade(flow3r.leds)).ok();
-    spawner.spawn(demo_tasks::display_demo(flow3r.display)).ok();
+    // spawner.spawn(demo_tasks::display_demo(flow3r.display)).ok();
 
-    loop {
-        Timer::after(Duration::from_secs(10)).await
-    }
+    Timer::after(Duration::from_secs(3)).await;
+
+    main_menu(flow3r.display, flow3r.inputs).await
 }
diff --git a/src/runtime.rs b/src/runtime.rs
index 7834e7f0331c48b2e0cda0a3ffeb350aa6085b67..2794f2126796099b19b1f9b5d4a398c6a927f5b4 100644
--- a/src/runtime.rs
+++ b/src/runtime.rs
@@ -176,12 +176,12 @@ async fn init_runtime() {
     // Init Flow3r components
 
     let badgelink = BadgeLink::new(i2c_busmanager.acquire_i2c());
-    let imu = ImuHandler::new(i2c_busmanager.acquire_i2c());
+    //let imu = ImuHandler::new(i2c_busmanager.acquire_i2c());
     let inputs = InputHandler;
     let captouch = CapTouchHandler;
     let leds = init_leds(pulse.channel0, io.pins.gpio14);
 
-    let flow3r = Flow3r::new(badgelink, captouch, display, imu, inputs, leds);
+    let flow3r = Flow3r::new(badgelink, captouch, display, inputs, leds);
 
     // Spawn background tasks