diff --git a/Cargo.lock b/Cargo.lock
index 5f71d30d523e4b5d5267330b869a27fa1b14f423..71c5127a5fb824b576c83ad68aa547adaa38c551 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -711,6 +711,18 @@ dependencies = [
  "tinybmp",
 ]
 
+[[package]]
+name = "flow3-rs-rt"
+version = "0.1.0"
+dependencies = [
+ "embassy-executor",
+ "embassy-time",
+ "esp32s3-hal",
+ "flow3-rs",
+ "shared-bus",
+ "static_cell",
+]
+
 [[package]]
 name = "fnv"
 version = "1.0.7"
@@ -1298,6 +1310,39 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "template"
+version = "0.1.0"
+dependencies = [
+ "ad7147",
+ "bmi270",
+ "byte-slice-cast 1.2.2",
+ "display-interface 0.5.0-alpha.1",
+ "embassy-executor",
+ "embassy-futures",
+ "embassy-net",
+ "embassy-net-badgelink",
+ "embassy-sync",
+ "embassy-time",
+ "embedded-dma",
+ "embedded-graphics",
+ "embedded-graphics-framebuf",
+ "embedded-hal 0.2.7",
+ "embedded-hal 1.0.0-alpha.10",
+ "embedded-hal-async",
+ "embedded-hal-bus",
+ "esp-backtrace",
+ "esp-println",
+ "esp32s3-hal",
+ "flow3-rs",
+ "flow3-rs-rt",
+ "heapless",
+ "smart-leds",
+ "smoltcp",
+ "static_cell",
+ "tinybmp",
+]
+
 [[package]]
 name = "tinybmp"
 version = "0.5.0"
diff --git a/Cargo.toml b/Cargo.toml
index 7012879e956bd60a02f32b4fae1169913c2ac42f..9d8e4932db0c838c91ce532d5d8cec637922a0da 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,12 +4,11 @@ version = "0.1.0"
 edition = "2021"
 authors = ["zdmx <hi@zdmx.me>"]
 
-
 [dependencies]
-ad7147 = { path = "./ad7147" }
-bmi270 = { path = "./bmi270" }
+ad7147 = { path = "./vendor/ad7147" }
+bmi270 = { path = "./vendor/bmi270" }
 byte-slice-cast = { version = "1.2.2", default-features = false }
-display-interface = { path = "./display-interface", features = ["nightly", "async", "dma"] }
+display-interface = { path = "./vendor/display-interface", features = ["nightly", "async", "dma"] }
 embassy-executor = { version = "0.2.0", features = ["nightly", "arch-xtensa", "executor-thread", "integrated-timers"] }
 embassy-futures = "0.1.0"
 embassy-net = { version = "0.1.0", features = ["medium-ethernet", "udp", "proto-ipv6", "nightly", "unstable-traits"] }
@@ -26,7 +25,7 @@ embedded-hal-bus = "0.1.0-alpha.2"
 esp-backtrace = { version = "0.7.0", features = ["esp32s3", "panic-handler", "exception-handler", "print-uart"] }
 esp-hal-smartled = { version = "0.4.0", features = ["esp32s3"] }
 esp-println = { version = "0.5.0", features = ["esp32s3"] }
-gc9a01 = { path = "./gc9a01" }
+gc9a01 = { path = "./vendor/gc9a01" }
 hal = { package = "esp32s3-hal", version = "0.11.0", features = ["embassy", "async", "embassy-time", "embassy-time-systick"] }
 heapless = "0.7.16"
 port-expander = "0.4.0"
@@ -35,3 +34,12 @@ smart-leds = "0.3.0"
 smoltcp = { version = "0.10.0", default-features = false }
 static_cell = "1.2.0"
 tinybmp = "0.5.0"
+
+[workspace]
+members = [
+    "vendor/ad7147",
+    "vendor/bmi270",
+    "embassy-net-badgelink",
+    "flow3-rs-rt",
+    "template"
+]
\ No newline at end of file
diff --git a/flow3-rs-rt/Cargo.toml b/flow3-rs-rt/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b8c16fe4f95f22317968a2dc19d742104febf857
--- /dev/null
+++ b/flow3-rs-rt/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "flow3-rs-rt"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+embassy-executor = { version = "0.2.0", features = ["nightly", "arch-xtensa", "executor-thread", "integrated-timers"] }
+hal = { package = "esp32s3-hal", version = "0.10.0", features = ["embassy", "async", "embassy-time", "embassy-time-systick"] }
+embassy-time = { version = "=0.1.1", features = ["nightly", "unstable-traits"] }
+static_cell = "1.2.0"
+shared-bus = { version = "0.3.0", features = ["xtensa"] }
+flow3-rs = { path = "../" }
\ No newline at end of file
diff --git a/flow3-rs-rt/src/lib.rs b/flow3-rs-rt/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c05c5b6fefd173747e8cbc28ff1471d667f3ec59
--- /dev/null
+++ b/flow3-rs-rt/src/lib.rs
@@ -0,0 +1,5 @@
+#![no_std]
+#![feature(type_alias_impl_trait)]
+
+mod runtime;
+pub use runtime::start_runtime;
\ No newline at end of file
diff --git a/src/runtime.rs b/flow3-rs-rt/src/runtime.rs
similarity index 76%
rename from src/runtime.rs
rename to flow3-rs-rt/src/runtime.rs
index f4811823f27d8d87f3e41b326d5ad782769d634b..2b860e28560f1f7e2c4142d717fc444b554cf1a7 100644
--- a/src/runtime.rs
+++ b/flow3-rs-rt/src/runtime.rs
@@ -1,6 +1,5 @@
-use embassy_executor::{Executor, Spawner};
+use embassy_executor::{Executor, Spawner, SpawnToken};
 use embassy_time::{Duration, Timer};
-use esp_println::println;
 use hal::{
     clock::{ClockControl, Clocks},
     cpu_control::CpuControl,
@@ -15,7 +14,7 @@ use hal::{
 };
 use static_cell::StaticCell;
 
-use crate::flow3r::{
+use flow3_rs::{
     badgelink::BadgeLink,
     captouch::{captouch_controller, CaptouchHandler},
     display::Display,
@@ -24,7 +23,6 @@ use crate::flow3r::{
     leds::init_leds,
     Flow3r,
 };
-use crate::main;
 
 const READ_BUF_SIZE: usize = 64;
 
@@ -33,10 +31,10 @@ static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 //static APP_CORE_EXECUTOR: StaticCell<Executor> = StaticCell::new();
 static CLOCKS: StaticCell<Clocks> = StaticCell::new();
 
-pub fn start_runtime() -> ! {
+pub fn start_runtime(main_function: fn(Flow3r) -> SpawnToken<*mut fn()>) -> ! {
     let executor = EXECUTOR.init(Executor::new());
     executor.run(|spawner| {
-        spawner.spawn(init_runtime()).ok();
+        spawner.spawn(init_runtime(main_function)).ok();
     });
 }
 
@@ -55,8 +53,7 @@ async fn start_app_core(mut cpu_control: CpuControl) -> ! {
 }
 
 #[embassy_executor::task]
-async fn init_runtime() {
-    esp_println::println!("Init!");
+async fn init_runtime(main_function: fn(Flow3r) -> SpawnToken<*mut fn()>) {
     let peripherals = Peripherals::take();
     let mut system = peripherals.SYSTEM.split();
     let clocks = CLOCKS.init(ClockControl::boot_defaults(system.clock_control).freeze());
@@ -195,7 +192,7 @@ async fn init_runtime() {
 
     // Init Flow3r components
 
-    let mut badgelink = BadgeLink::new(i2c_busmanager.acquire_i2c());
+    let badgelink = BadgeLink::new(i2c_busmanager.acquire_i2c());
     let imu = ImuHandler::new(i2c_busmanager.acquire_i2c());
     let inputs = InputHandler;
     let captouch = CaptouchHandler;
@@ -224,55 +221,5 @@ async fn init_runtime() {
         .ok();
 
     // Hand over to main task
-    spawner.spawn(main(flow3r)).ok();
-    /*spawner.spawn(test_pins_a(io.pins.gpio5)).unwrap();
-    spawner.spawn(test_pins_b(io.pins.gpio6)).unwrap();
-    spawner.spawn(test_pins_c(io.pins.gpio4)).unwrap();
-    spawner.spawn(test_pins_d(io.pins.gpio7)).unwrap();*/
-}
-
-/*
-#[embassy_executor::task]
-async fn test_pins_a(pin: Gpio5<Unknown>) -> ! {
-    let mut pin = pin.into_push_pull_output();
-    println!("toggle task running");
-    loop {
-        pin.set_high().unwrap();
-        Timer::after(Duration::from_secs(1)).await;
-        pin.set_low().unwrap();
-        Timer::after(Duration::from_secs(1)).await;
-    }
-}
-
-
-#[embassy_executor::task]
-async fn test_pins_d(pin: Gpio7<Unknown>) -> ! {
-    let mut pin = pin.into_push_pull_output();
-    println!("toggle task running");
-    loop {
-        pin.set_high().unwrap();
-        Timer::after(Duration::from_secs(1)).await;
-        pin.set_low().unwrap();
-        Timer::after(Duration::from_secs(1)).await;
-    }
-}
-
-#[embassy_executor::task]
-async fn test_pins_b(pin: Gpio6<Unknown>) -> ! {
-    let mut pin = pin.into_floating_input();
-    println!("wait task running");
-    loop {
-        pin.wait_for_any_edge().await.unwrap();
-        println!("pin 5 changed, is now {}", pin.is_high().unwrap());
-    }
-}
-
-#[embassy_executor::task]
-async fn test_pins_c(pin: Gpio4<Unknown>) -> ! {
-    let mut pin = pin.into_floating_input();
-    println!("wait task running");
-    loop {
-        pin.wait_for_any_edge().await.unwrap();
-        println!("pin 4 changed, is now {}", pin.is_high().unwrap());
-    }
-} */
\ No newline at end of file
+    spawner.spawn::<*mut fn()>(main_function(flow3r)).ok();
+}
\ No newline at end of file
diff --git a/src/flow3r/badgelink/badgenet.rs b/src/badgelink/badgenet.rs
similarity index 94%
rename from src/flow3r/badgelink/badgenet.rs
rename to src/badgelink/badgenet.rs
index 42c2fe117f41e3521e550931d69cd80c7928fb3d..9cf49d34e29909b2d4cd13e4214ed4e4c414f840 100644
--- a/src/flow3r/badgelink/badgenet.rs
+++ b/src/badgelink/badgenet.rs
@@ -1,13 +1,13 @@
 use embassy_executor::Spawner;
-use embassy_net::{Config, Ipv6Address, Ipv6Cidr, Stack, StackResources, StaticConfigV6};
+use embassy_net::{Config, Stack, StackResources};
 use embassy_net_badgelink::{Device, Runner, State};
 use esp_println::println;
 use hal::{
     efuse::Efuse,
-    peripherals::{UART0, UART1, UART2},
-    Rng, Uart,
+    peripherals::{UART1, UART2},
+    Uart,
 };
-use heapless::Vec;
+
 use static_cell::StaticCell;
 
 static STATE_LEFT: StaticCell<State<8, 8>> = StaticCell::new();
diff --git a/src/flow3r/badgelink/mod.rs b/src/badgelink/mod.rs
similarity index 94%
rename from src/flow3r/badgelink/mod.rs
rename to src/badgelink/mod.rs
index ab584afb9d7dd671bfdab5bbf4a72a5502cf44fb..c8967c3e2f52cca07595845fe0f88ccb0eeb6fbf 100644
--- a/src/flow3r/badgelink/mod.rs
+++ b/src/badgelink/mod.rs
@@ -1,4 +1,4 @@
-use hal::{i2c::I2C, peripherals::{I2C0, UART0, UART1}, Uart, Rng};
+use hal::{i2c::I2C, peripherals::I2C0};
 use port_expander::{dev::max7321::Driver, Max7321};
 use shared_bus::{I2cProxy, NullMutex, XtensaMutex};
 
diff --git a/src/flow3r/captouch.rs b/src/captouch.rs
similarity index 88%
rename from src/flow3r/captouch.rs
rename to src/captouch.rs
index 9a7c977cd4e56698bb010f50547925c33fcc5b3c..108ff1636fb09737c987a89ad611b40003b2c900 100644
--- a/src/flow3r/captouch.rs
+++ b/src/captouch.rs
@@ -7,7 +7,6 @@ use embassy_futures::select::{select, Either};
 use embassy_sync::{
     blocking_mutex::raw::CriticalSectionRawMutex,
     mutex::Mutex,
-    pubsub::{PubSubChannel, Subscriber},
 };
 use embassy_time::Delay;
 use embedded_hal_async::digital::Wait;
@@ -19,50 +18,37 @@ use hal::{
 };
 use shared_bus::{I2cProxy, XtensaMutex};
 
-static CAPTOUCH_CHANNEL: PubSubChannel<CriticalSectionRawMutex, Flow3rCaptouchEvent, 32, 32, 32> =
-    PubSubChannel::<CriticalSectionRawMutex, Flow3rCaptouchEvent, 32, 32, 32>::new();
-
-pub type CaptouchEventListener =
-    Subscriber<'static, CriticalSectionRawMutex, Flow3rCaptouchEvent, 32, 32, 32>;
-
 static PETALS: Mutex<CriticalSectionRawMutex, [Flow3rPetal; 10]> = Mutex::new([
-    Flow3rPetal::new(0, Flow3rCaptouchController::TOP),
-    Flow3rPetal::new(1, Flow3rCaptouchController::BOTTOM),
-    Flow3rPetal::new(2, Flow3rCaptouchController::TOP),
-    Flow3rPetal::new(3, Flow3rCaptouchController::BOTTOM),
-    Flow3rPetal::new(4, Flow3rCaptouchController::TOP),
-    Flow3rPetal::new(5, Flow3rCaptouchController::BOTTOM),
-    Flow3rPetal::new(6, Flow3rCaptouchController::TOP),
-    Flow3rPetal::new(7, Flow3rCaptouchController::BOTTOM),
-    Flow3rPetal::new(8, Flow3rCaptouchController::TOP),
-    Flow3rPetal::new(9, Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(Flow3rCaptouchController::BOTTOM),
 ]);
 
-#[derive(Debug, Clone, Copy)]
-struct Flow3rCaptouchEvent {
-    petals: [Flow3rPetal; 5],
-}
 
 #[derive(Debug, Clone, Copy)]
-pub enum Flow3rPetal {
+enum Flow3rPetal {
     TOP {
-        number: u8,
         ccw: Flow3rPetalPart,
         base: Flow3rPetalPart,
         cw: Flow3rPetalPart,
     },
     BOTTOM {
-        number: u8,
         base: Flow3rPetalPart,
         tip: Flow3rPetalPart,
     },
 }
 
 impl Flow3rPetal {
-    const fn new(num: u8, pos: Flow3rCaptouchController) -> Flow3rPetal {
+    const fn new(pos: Flow3rCaptouchController) -> Flow3rPetal {
         match pos {
             Flow3rCaptouchController::TOP => Self::TOP {
-                number: num,
                 ccw: Flow3rPetalPart {
                     pressed: false,
                     raw: 0,
@@ -77,7 +63,6 @@ impl Flow3rPetal {
                 },
             },
             Flow3rCaptouchController::BOTTOM => Self::BOTTOM {
-                number: num,
                 base: Flow3rPetalPart {
                     pressed: false,
                     raw: 0,
@@ -93,48 +78,22 @@ impl Flow3rPetal {
     pub fn pressed(&self) -> bool {
         match self {
             Flow3rPetal::TOP {
-                number,
                 ccw,
                 base,
                 cw,
             } => ccw.pressed | base.pressed | cw.pressed,
-            Flow3rPetal::BOTTOM { number, base, tip } => base.pressed | tip.pressed,
+            Flow3rPetal::BOTTOM { base, tip } => base.pressed | tip.pressed,
         }
     }
 
     pub fn position(&self) -> i32 {
         match self {
             Flow3rPetal::TOP {
-                number,
                 ccw,
                 base,
                 cw,
             } => (ccw.raw as i32 + cw.raw as i32) / 2 - base.raw as i32,
-            Flow3rPetal::BOTTOM { number, base, tip } => base.raw as i32 + tip.raw as i32 / 2,
-        }
-    }
-
-    pub fn number(&self) -> u8 {
-        match self {
-            Flow3rPetal::TOP {
-                number,
-                ccw,
-                base,
-                cw,
-            } => *number,
-            Flow3rPetal::BOTTOM { number, base, tip } => *number,
-        }
-    }
-
-    fn update(&mut self, pressed: &[bool], values: &[u16]) {
-        match self {
-            Flow3rPetal::TOP {
-                number,
-                ccw,
-                base,
-                cw,
-            } => ccw.pressed = pressed[0],
-            Flow3rPetal::BOTTOM { number, base, tip } => todo!(),
+            Flow3rPetal::BOTTOM {base, tip } => base.raw as i32 + tip.raw as i32 / 2,
         }
     }
 }
@@ -478,15 +437,15 @@ pub async fn captouch_controller(
     loop {
         match select(cap_bot_int.wait_for_low(), cap_top_int.wait_for_low()).await {
             Either::First(_) => {
-                let interrupts = ad7147_bot.read_interrupt_registers().unwrap();
+                let _ = ad7147_bot.read_interrupt_registers().unwrap();
                 let measurements_bot = ad7147_bot.read_all_stages().unwrap();
                 // println!("pad 0: {}, {}, {}, {}", measurements_bot[0], measurements_bot[1], interrupts[1] & (1 << 0) != 0, interrupts[1] & (1 << 1) != 0);
-                update_petals_bot(interrupts[1], measurements_bot).await;
+                update_petals_bot(measurements_bot).await;
             }
             Either::Second(_) => {
-                let interrupts = ad7147_top.read_interrupt_registers().unwrap();
+                let _ = ad7147_top.read_interrupt_registers().unwrap();
                 let measurements_top = ad7147_top.read_all_stages().unwrap();
-                update_petals_top(interrupts[1], measurements_top).await;
+                update_petals_top(measurements_top).await;
             }
         }
     }
@@ -515,7 +474,7 @@ static PETAL_MAPPING_TOP: [(usize, PetalPosition); 12] = [
     (6, PetalPosition::BASE),
 ];
 
-async fn update_petals_top(interrupts: u16, measurements: [u16; 12]) {
+async fn update_petals_top(measurements: [u16; 12]) {
     let mut petals = PETALS.lock().await;
     for (i, m) in PETAL_MAPPING_TOP.iter().enumerate() {
         let pressed = measurements[i] > 50000;
@@ -575,7 +534,7 @@ static PETAL_MAPPPING_BOT: [(usize, PetalPosition); 12] = [
     (2, PetalPosition::CW),
 ];
 
-async fn update_petals_bot(interrupts: u16, measurements: [u16; 12]) {
+async fn update_petals_bot(measurements: [u16; 12]) {
     let mut petals = PETALS.lock().await;
     for (i, m) in PETAL_MAPPPING_BOT.iter().enumerate() {
         let pressed = measurements[i] > 40000;
diff --git a/src/flow3r/display/backlight.rs b/src/display/backlight.rs
similarity index 100%
rename from src/flow3r/display/backlight.rs
rename to src/display/backlight.rs
diff --git a/src/flow3r/display/display_driver.rs b/src/display/display_driver.rs
similarity index 100%
rename from src/flow3r/display/display_driver.rs
rename to src/display/display_driver.rs
diff --git a/src/flow3r/display/display_interface.rs b/src/display/display_interface.rs
similarity index 100%
rename from src/flow3r/display/display_interface.rs
rename to src/display/display_interface.rs
diff --git a/src/flow3r/display/framebuffer.rs b/src/display/framebuffer.rs
similarity index 100%
rename from src/flow3r/display/framebuffer.rs
rename to src/display/framebuffer.rs
diff --git a/src/flow3r/display/mod.rs b/src/display/mod.rs
similarity index 100%
rename from src/flow3r/display/mod.rs
rename to src/display/mod.rs
diff --git a/src/flow3r/imu.rs b/src/imu.rs
similarity index 95%
rename from src/flow3r/imu.rs
rename to src/imu.rs
index c6b012d816a634377ca70f3710ac9e62fd3a1182..f61ed7e0897b1220f991b5532079f89d30a678a8 100644
--- a/src/flow3r/imu.rs
+++ b/src/imu.rs
@@ -11,7 +11,6 @@ impl ImuHandler {
     pub fn new(i2c: I2cProxy<'static, XtensaMutex<I2C<'static, I2C0>>>) -> Self {
         let mut bmi270 = Bmi270::new_i2c(i2c, bmi270::I2cAddr::Default, bmi270::Burst::Max);
 
-        /*
         if let Some(chip_id) = bmi270.get_chip_id().ok() {
             println!("imu chip id: {}", chip_id);
         }
@@ -24,7 +23,7 @@ impl ImuHandler {
             acc_en: true,
             temp_en: false,
         };
-        bmi270.set_pwr_ctrl(pwr_ctrl).ok();*/
+        bmi270.set_pwr_ctrl(pwr_ctrl).ok();
         Self { imu: bmi270 }
     }
 
diff --git a/src/flow3r/input.rs b/src/input.rs
similarity index 100%
rename from src/flow3r/input.rs
rename to src/input.rs
diff --git a/src/flow3r/leds.rs b/src/leds.rs
similarity index 100%
rename from src/flow3r/leds.rs
rename to src/leds.rs
diff --git a/src/flow3r/mod.rs b/src/lib.rs
similarity index 93%
rename from src/flow3r/mod.rs
rename to src/lib.rs
index 39f820ecba487970308fa5029d718c4c0a5b7ddd..222a2d5812e3b4e7fc8b00d465e6d3ef98f124d7 100644
--- a/src/flow3r/mod.rs
+++ b/src/lib.rs
@@ -1,5 +1,7 @@
-use hal::{Uart, Rng};
-use hal::peripherals::{UART0, UART1};
+#![no_std]
+#![feature(type_alias_impl_trait, async_fn_in_trait)]
+
+use hal::Rng;
 
 use self::badgelink::BadgeLink;
 use self::badgelink::badgenet::{BadgenetUartLeft, BadgenetUartRight};
@@ -16,7 +18,6 @@ pub mod imu;
 pub mod input;
 pub mod leds;
 pub mod sdcard;
-pub mod ui;
 
 pub struct Flow3r {
     pub badgelink: BadgeLink,
diff --git a/src/flow3r/sdcard.rs b/src/sdcard.rs
similarity index 100%
rename from src/flow3r/sdcard.rs
rename to src/sdcard.rs
diff --git a/template/Cargo.toml b/template/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..d6a7ab6dd3cf4adba87b0def0fddfa4cbd7202f6
--- /dev/null
+++ b/template/Cargo.toml
@@ -0,0 +1,35 @@
+[package]
+name = "template"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+ad7147 = { path = "../vendor/ad7147" }
+bmi270 = { path = "../vendor/bmi270" }
+byte-slice-cast = { version = "1.2.2", default-features = false }
+display-interface = { path = "../vendor/display-interface", features = ["nightly", "async", "dma"] }
+embassy-executor = { version = "0.2.0", features = ["nightly", "arch-xtensa", "executor-thread", "integrated-timers"] }
+embassy-futures = "0.1.0"
+embassy-net = { version = "0.1.0", features = ["medium-ethernet", "udp", "proto-ipv6", "nightly", "unstable-traits"] }
+embassy-net-badgelink = { path = "../embassy-net-badgelink" }
+embassy-sync = "0.2.0"
+embassy-time = { version = "=0.1.1", features = ["nightly", "unstable-traits"] }
+embedded-dma = "0.2.0"
+embedded-graphics = "0.8.0"
+embedded-graphics-framebuf = "0.5.0"
+embedded-hal = "0.2.7"
+embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
+embedded-hal-async = "0.2.0-alpha.1"
+embedded-hal-bus = "0.1.0-alpha.2"
+esp-backtrace = { version = "0.7.0", features = ["esp32s3", "panic-handler", "exception-handler", "print-uart"] }
+esp-println = { version = "0.5.0", features = ["esp32s3"] }
+hal = { package = "esp32s3-hal", version = "0.10.0", features = ["embassy", "async", "embassy-time", "embassy-time-systick"] }
+heapless = "0.7.16"
+smart-leds = "0.3.0"
+smoltcp = { version = "0.10.0", default-features = false }
+static_cell = "1.2.0"
+tinybmp = "0.5.0"
+flow3-rs = { path = "../" }
+flow3-rs-rt = { path = "../flow3-rs-rt" }
\ No newline at end of file
diff --git a/src/demo_tasks.rs b/template/src/demo_tasks.rs
similarity index 96%
rename from src/demo_tasks.rs
rename to template/src/demo_tasks.rs
index d4282c8be4c7986330bedeb5448c7c0712121b49..5ee0e56180f56ce6a27ec5552151bea72f5bd009 100644
--- a/src/demo_tasks.rs
+++ b/template/src/demo_tasks.rs
@@ -1,4 +1,4 @@
-use crate::flow3r::{captouch::CaptouchHandler, display::Display, imu::ImuHandler, badgelink::{BadgeLink, badgenet::{BadgenetUartLeft, BadgenetUartRight, start_badgenet_left, start_badgenet_right}}};
+use flow3_rs::{captouch::CaptouchHandler, display::Display, imu::ImuHandler, badgelink::{BadgeLink, badgenet::{BadgenetUartLeft, BadgenetUartRight, start_badgenet_left, start_badgenet_right}}};
 use embassy_executor::Spawner;
 use embassy_futures::select::{select, select3, Either, Either3};
 use embassy_net::{udp::{UdpSocket, PacketMetadata}, Ipv6Address, Stack, StaticConfigV6, Config, Ipv6Cidr};
@@ -14,17 +14,17 @@ use embedded_graphics::{
 };
 use esp_backtrace as _;
 use esp_println::println;
-use hal::{Rng, uart};
+use hal::Rng;
 use heapless::Vec;
 use smoltcp::wire::IpEndpoint;
 use tinybmp::Bmp;
 
 use smart_leds::SmartLedsWrite;
 
-use crate::flow3r::input::InputHandler;
+use flow3_rs::input::InputHandler;
 
 #[embassy_executor::task]
-pub async fn leds_fade(mut leds: crate::flow3r::leds::Leds) -> ! {
+pub async fn leds_fade(mut leds: flow3_rs::leds::Leds) -> ! {
     let mut b = (30, false);
 
     loop {
@@ -35,11 +35,11 @@ pub async fn leds_fade(mut leds: crate::flow3r::leds::Leds) -> ! {
         .expect("failed to set leds");
 
         Timer::after(Duration::from_millis(30)).await;
-        b = crate::flow3r::leds::brightness_fade_in_out(b, 30, 0);
+        b = flow3_rs::leds::brightness_fade_in_out(b, 30, 0);
     }
 }
 
-pub async fn display_demo(display: &mut crate::flow3r::display::Display) {
+pub async fn display_demo(display: &mut flow3_rs::display::Display) {
     let input = InputHandler;
     let mut inputs = input.split();
 
@@ -94,7 +94,7 @@ async fn move_rectangle<'a>(
 }
 
 pub async fn draw_start_screen(display: &mut Display) {
-    let bmp_data = include_bytes!("../img/logo.bmp");
+    let bmp_data = include_bytes!("../../img/logo.bmp");
     let bmp = Bmp::from_slice(bmp_data).unwrap();
     display
         .fill_solid(&display.bounding_box(), Rgb565::WHITE)
diff --git a/src/main.rs b/template/src/main.rs
similarity index 57%
rename from src/main.rs
rename to template/src/main.rs
index 357e55c82638b3d1eea0b593e303fbc9fd65c12c..d027f27f94c11ff6e67d62b1f55c46a012e9eb6f 100644
--- a/src/main.rs
+++ b/template/src/main.rs
@@ -2,25 +2,25 @@
 #![no_main]
 #![feature(type_alias_impl_trait)]
 #![feature(async_fn_in_trait)]
-#![feature(slice_as_chunks)]
 
 mod demo_tasks;
-mod flow3r;
-mod runtime;
+mod ui;
 
 use demo_tasks::{draw_start_screen, badgelink_demo};
 use embassy_executor::Spawner;
 use embassy_time::{Duration, Timer};
 
 use esp_backtrace as _;
-use flow3r::{ui::main_menu::main_menu, Flow3r};
 use hal::prelude::*;
 
-use runtime::start_runtime;
+use flow3_rs::Flow3r;
+use flow3_rs_rt::start_runtime;
+
+use crate::ui::main_menu::main_menu;
 
 #[entry]
 fn runtime() -> ! {
-    start_runtime()
+    start_runtime(main)
 }
 
 #[embassy_executor::task]
@@ -30,9 +30,7 @@ async fn main(mut flow3r: Flow3r) -> ! {
     let spawner = Spawner::for_current_executor().await;
     spawner.spawn(demo_tasks::leds_fade(flow3r.leds)).ok();
 
-    //Timer::after(Duration::from_secs(3)).await;
-
-    //badgelink_demo(&mut flow3r.badgelink, flow3r.uart0, flow3r.uart1, flow3r.rng).await;
+    Timer::after(Duration::from_secs(2)).await;
 
-    main_menu(flow3r.display, flow3r.inputs, flow3r.imu, flow3r.badgelink, flow3r.uart0, flow3r.uart1, flow3r.rng).await
+    main_menu(flow3r.display, flow3r.inputs, flow3r.imu).await
 }
diff --git a/src/flow3r/ui/main_menu.rs b/template/src/ui/main_menu.rs
similarity index 68%
rename from src/flow3r/ui/main_menu.rs
rename to template/src/ui/main_menu.rs
index dd602dd75beeb7720b2fe6a1c34f67916bdd2978..6890b74147da428889476b0d193e6062d65188da 100644
--- a/src/flow3r/ui/main_menu.rs
+++ b/template/src/ui/main_menu.rs
@@ -6,24 +6,15 @@ use embedded_graphics::{
     prelude::*,
     text::Text,
 };
-use hal::Rng;
-use static_cell::StaticCell;
 
-use crate::{
-    demo_tasks::{display_demo, imu_demo, captouch_demo, badgelink_demo},
-    flow3r::{display::Display, input::InputHandler, imu::ImuHandler, badgelink::{badgenet::{BadgenetUartLeft, BadgenetUartRight}, BadgeLink}},
-};
+use flow3_rs::{display::Display, input::InputHandler, imu::ImuHandler};
 
-static UART_LEFT: StaticCell<BadgenetUartLeft> = StaticCell::new();
-static UART_RIGHT: StaticCell<BadgenetUartRight> = StaticCell::new();
+use crate::demo_tasks::{display_demo, imu_demo, captouch_demo};
 
-pub async fn main_menu(mut display: Display, inputs: InputHandler, mut imu: ImuHandler, mut badgelink: BadgeLink, uart0: BadgenetUartLeft, uart1: BadgenetUartRight, mut rng: &'static mut Rng) -> ! {
+pub async fn main_menu(mut display: Display, inputs: InputHandler, mut imu: ImuHandler) -> ! {
     let mut inputs = inputs.split();
 
-    let mut uart0 = UART_LEFT.init(uart0);
-    let mut uart1 = UART_RIGHT.init(uart1);
-
-    let apps = ["input_test", "imu_test", "captouch_test", "badgenet_test"];
+    let apps = ["input_test", "imu_test", "captouch_test"];
     let mut selected = 0usize;
 
     display
@@ -47,7 +38,7 @@ pub async fn main_menu(mut display: Display, inputs: InputHandler, mut imu: ImuH
         .await
         {
             Either3::First(_) => {
-                (uart0, uart1, rng) = start_current_app(apps[selected], &mut display, &mut imu, &mut badgelink, uart0, uart1, rng).await;
+                start_current_app(apps[selected], &mut display, &mut imu).await;
                 display
                     .fill_solid(&display.bounding_box(), Rgb565::BLACK)
                     .unwrap();
@@ -111,12 +102,11 @@ async fn play_transition_animation<'a>(
     }
 }
 
-async fn start_current_app(app: &str, display: &mut Display, imu: &mut ImuHandler, badgelink: &mut BadgeLink,  uart0: &'static mut BadgenetUartLeft, uart1: &'static mut BadgenetUartRight, rng: &'static mut Rng) -> (&'static mut BadgenetUartLeft, &'static mut BadgenetUartRight,  &'static mut Rng) {
+async fn start_current_app(app: &str, display: &mut Display, imu: &mut ImuHandler) {
     match app {
-        "input_test" => {display_demo(display).await; (uart0, uart1, rng)}
-        "imu_test" =>{imu_demo(display, imu).await; (uart0, uart1, rng)}
-        "captouch_test" => {captouch_demo(display).await; (uart0, uart1, rng)}
-        //"badgenet_test" => badgelink_demo(badgelink, uart0, uart1, rng).await,
-        _ => (uart0, uart1, rng),
+        "input_test" => display_demo(display).await,
+        "imu_test" => imu_demo(display, imu).await,
+        "captouch_test" => captouch_demo(display).await,
+        _ => (),
     }
 }
diff --git a/src/flow3r/ui/mod.rs b/template/src/ui/mod.rs
similarity index 100%
rename from src/flow3r/ui/mod.rs
rename to template/src/ui/mod.rs
diff --git a/ad7147/.gitignore b/vendor/ad7147/.gitignore
similarity index 100%
rename from ad7147/.gitignore
rename to vendor/ad7147/.gitignore
diff --git a/ad7147/Cargo.lock b/vendor/ad7147/Cargo.lock
similarity index 100%
rename from ad7147/Cargo.lock
rename to vendor/ad7147/Cargo.lock
diff --git a/ad7147/Cargo.toml b/vendor/ad7147/Cargo.toml
similarity index 100%
rename from ad7147/Cargo.toml
rename to vendor/ad7147/Cargo.toml
diff --git a/ad7147/src/device.rs b/vendor/ad7147/src/device.rs
similarity index 100%
rename from ad7147/src/device.rs
rename to vendor/ad7147/src/device.rs
diff --git a/ad7147/src/driver.rs b/vendor/ad7147/src/driver.rs
similarity index 100%
rename from ad7147/src/driver.rs
rename to vendor/ad7147/src/driver.rs
diff --git a/ad7147/src/interrupt.rs b/vendor/ad7147/src/interrupt.rs
similarity index 100%
rename from ad7147/src/interrupt.rs
rename to vendor/ad7147/src/interrupt.rs
diff --git a/ad7147/src/lib.rs b/vendor/ad7147/src/lib.rs
similarity index 100%
rename from ad7147/src/lib.rs
rename to vendor/ad7147/src/lib.rs
diff --git a/ad7147/src/stage.rs b/vendor/ad7147/src/stage.rs
similarity index 100%
rename from ad7147/src/stage.rs
rename to vendor/ad7147/src/stage.rs
diff --git a/bmi270/.gitignore b/vendor/bmi270/.gitignore
similarity index 100%
rename from bmi270/.gitignore
rename to vendor/bmi270/.gitignore
diff --git a/bmi270/Cargo.toml b/vendor/bmi270/Cargo.toml
similarity index 100%
rename from bmi270/Cargo.toml
rename to vendor/bmi270/Cargo.toml
diff --git a/bmi270/LICENSE b/vendor/bmi270/LICENSE
similarity index 100%
rename from bmi270/LICENSE
rename to vendor/bmi270/LICENSE
diff --git a/bmi270/README.md b/vendor/bmi270/README.md
similarity index 100%
rename from bmi270/README.md
rename to vendor/bmi270/README.md
diff --git a/bmi270/src/bmi270.rs b/vendor/bmi270/src/bmi270.rs
similarity index 100%
rename from bmi270/src/bmi270.rs
rename to vendor/bmi270/src/bmi270.rs
diff --git a/bmi270/src/config.rs b/vendor/bmi270/src/config.rs
similarity index 100%
rename from bmi270/src/config.rs
rename to vendor/bmi270/src/config.rs
diff --git a/bmi270/src/interface.rs b/vendor/bmi270/src/interface.rs
similarity index 100%
rename from bmi270/src/interface.rs
rename to vendor/bmi270/src/interface.rs
diff --git a/bmi270/src/lib.rs b/vendor/bmi270/src/lib.rs
similarity index 100%
rename from bmi270/src/lib.rs
rename to vendor/bmi270/src/lib.rs
diff --git a/bmi270/src/registers.rs b/vendor/bmi270/src/registers.rs
similarity index 100%
rename from bmi270/src/registers.rs
rename to vendor/bmi270/src/registers.rs
diff --git a/bmi270/src/types.rs b/vendor/bmi270/src/types.rs
similarity index 100%
rename from bmi270/src/types.rs
rename to vendor/bmi270/src/types.rs
diff --git a/display-interface/.github/workflows/ci.yml b/vendor/display-interface/.github/workflows/ci.yml
similarity index 100%
rename from display-interface/.github/workflows/ci.yml
rename to vendor/display-interface/.github/workflows/ci.yml
diff --git a/display-interface/.github/workflows/clippy.yml b/vendor/display-interface/.github/workflows/clippy.yml
similarity index 100%
rename from display-interface/.github/workflows/clippy.yml
rename to vendor/display-interface/.github/workflows/clippy.yml
diff --git a/display-interface/.github/workflows/rustfmt.yml b/vendor/display-interface/.github/workflows/rustfmt.yml
similarity index 100%
rename from display-interface/.github/workflows/rustfmt.yml
rename to vendor/display-interface/.github/workflows/rustfmt.yml
diff --git a/display-interface/.gitignore b/vendor/display-interface/.gitignore
similarity index 100%
rename from display-interface/.gitignore
rename to vendor/display-interface/.gitignore
diff --git a/display-interface/Cargo.toml b/vendor/display-interface/Cargo.toml
similarity index 90%
rename from display-interface/Cargo.toml
rename to vendor/display-interface/Cargo.toml
index 45910227a794117a4972f91825e52d21b4315f43..14052ce1a93af920615b55c5a12659e98c501d5a 100644
--- a/display-interface/Cargo.toml
+++ b/vendor/display-interface/Cargo.toml
@@ -21,14 +21,6 @@ all-features = true
 async-trait = { version = "0.1.68", optional = true }
 embedded-dma = { version = "0.2.0", optional = true }
 
-[workspace]
-members = [
-    ".",
-    "i2c",
-    "parallel-gpio",
-    "spi",
-]
-
 [features]
 default = []
 async = ["async-trait"]
diff --git a/display-interface/LICENSE-APACHE b/vendor/display-interface/LICENSE-APACHE
similarity index 100%
rename from display-interface/LICENSE-APACHE
rename to vendor/display-interface/LICENSE-APACHE
diff --git a/display-interface/LICENSE-MIT b/vendor/display-interface/LICENSE-MIT
similarity index 100%
rename from display-interface/LICENSE-MIT
rename to vendor/display-interface/LICENSE-MIT
diff --git a/display-interface/i2c/Cargo.toml b/vendor/display-interface/i2c/Cargo.toml
similarity index 100%
rename from display-interface/i2c/Cargo.toml
rename to vendor/display-interface/i2c/Cargo.toml
diff --git a/display-interface/i2c/LICENSE-APACHE b/vendor/display-interface/i2c/LICENSE-APACHE
similarity index 100%
rename from display-interface/i2c/LICENSE-APACHE
rename to vendor/display-interface/i2c/LICENSE-APACHE
diff --git a/display-interface/i2c/LICENSE-MIT b/vendor/display-interface/i2c/LICENSE-MIT
similarity index 100%
rename from display-interface/i2c/LICENSE-MIT
rename to vendor/display-interface/i2c/LICENSE-MIT
diff --git a/display-interface/i2c/README.md b/vendor/display-interface/i2c/README.md
similarity index 100%
rename from display-interface/i2c/README.md
rename to vendor/display-interface/i2c/README.md
diff --git a/display-interface/i2c/src/asynch.rs b/vendor/display-interface/i2c/src/asynch.rs
similarity index 100%
rename from display-interface/i2c/src/asynch.rs
rename to vendor/display-interface/i2c/src/asynch.rs
diff --git a/display-interface/i2c/src/lib.rs b/vendor/display-interface/i2c/src/lib.rs
similarity index 100%
rename from display-interface/i2c/src/lib.rs
rename to vendor/display-interface/i2c/src/lib.rs
diff --git a/display-interface/parallel-gpio/Cargo.toml b/vendor/display-interface/parallel-gpio/Cargo.toml
similarity index 100%
rename from display-interface/parallel-gpio/Cargo.toml
rename to vendor/display-interface/parallel-gpio/Cargo.toml
diff --git a/display-interface/parallel-gpio/LICENSE-APACHE b/vendor/display-interface/parallel-gpio/LICENSE-APACHE
similarity index 100%
rename from display-interface/parallel-gpio/LICENSE-APACHE
rename to vendor/display-interface/parallel-gpio/LICENSE-APACHE
diff --git a/display-interface/parallel-gpio/LICENSE-MIT b/vendor/display-interface/parallel-gpio/LICENSE-MIT
similarity index 100%
rename from display-interface/parallel-gpio/LICENSE-MIT
rename to vendor/display-interface/parallel-gpio/LICENSE-MIT
diff --git a/display-interface/parallel-gpio/README.md b/vendor/display-interface/parallel-gpio/README.md
similarity index 100%
rename from display-interface/parallel-gpio/README.md
rename to vendor/display-interface/parallel-gpio/README.md
diff --git a/display-interface/parallel-gpio/src/lib.rs b/vendor/display-interface/parallel-gpio/src/lib.rs
similarity index 100%
rename from display-interface/parallel-gpio/src/lib.rs
rename to vendor/display-interface/parallel-gpio/src/lib.rs
diff --git a/display-interface/spi/Cargo.toml b/vendor/display-interface/spi/Cargo.toml
similarity index 100%
rename from display-interface/spi/Cargo.toml
rename to vendor/display-interface/spi/Cargo.toml
diff --git a/display-interface/spi/LICENSE-APACHE b/vendor/display-interface/spi/LICENSE-APACHE
similarity index 100%
rename from display-interface/spi/LICENSE-APACHE
rename to vendor/display-interface/spi/LICENSE-APACHE
diff --git a/display-interface/spi/LICENSE-MIT b/vendor/display-interface/spi/LICENSE-MIT
similarity index 100%
rename from display-interface/spi/LICENSE-MIT
rename to vendor/display-interface/spi/LICENSE-MIT
diff --git a/display-interface/spi/README.md b/vendor/display-interface/spi/README.md
similarity index 100%
rename from display-interface/spi/README.md
rename to vendor/display-interface/spi/README.md
diff --git a/display-interface/spi/src/asynch.rs b/vendor/display-interface/spi/src/asynch.rs
similarity index 100%
rename from display-interface/spi/src/asynch.rs
rename to vendor/display-interface/spi/src/asynch.rs
diff --git a/display-interface/spi/src/lib.rs b/vendor/display-interface/spi/src/lib.rs
similarity index 100%
rename from display-interface/spi/src/lib.rs
rename to vendor/display-interface/spi/src/lib.rs
diff --git a/display-interface/src/lib.rs b/vendor/display-interface/src/lib.rs
similarity index 100%
rename from display-interface/src/lib.rs
rename to vendor/display-interface/src/lib.rs
diff --git a/display-interface/src/prelude.rs b/vendor/display-interface/src/prelude.rs
similarity index 100%
rename from display-interface/src/prelude.rs
rename to vendor/display-interface/src/prelude.rs
diff --git a/gc9a01/Cargo.lock b/vendor/gc9a01/Cargo.lock
similarity index 100%
rename from gc9a01/Cargo.lock
rename to vendor/gc9a01/Cargo.lock
diff --git a/gc9a01/Cargo.toml b/vendor/gc9a01/Cargo.toml
similarity index 100%
rename from gc9a01/Cargo.toml
rename to vendor/gc9a01/Cargo.toml
diff --git a/gc9a01/LICENSE-APACHE b/vendor/gc9a01/LICENSE-APACHE
similarity index 100%
rename from gc9a01/LICENSE-APACHE
rename to vendor/gc9a01/LICENSE-APACHE
diff --git a/gc9a01/LICENSE-MIT b/vendor/gc9a01/LICENSE-MIT
similarity index 100%
rename from gc9a01/LICENSE-MIT
rename to vendor/gc9a01/LICENSE-MIT
diff --git a/gc9a01/src/brightness.rs b/vendor/gc9a01/src/brightness.rs
similarity index 100%
rename from gc9a01/src/brightness.rs
rename to vendor/gc9a01/src/brightness.rs
diff --git a/gc9a01/src/command.rs b/vendor/gc9a01/src/command.rs
similarity index 100%
rename from gc9a01/src/command.rs
rename to vendor/gc9a01/src/command.rs
diff --git a/gc9a01/src/display.rs b/vendor/gc9a01/src/display.rs
similarity index 100%
rename from gc9a01/src/display.rs
rename to vendor/gc9a01/src/display.rs
diff --git a/gc9a01/src/driver.rs b/vendor/gc9a01/src/driver.rs
similarity index 100%
rename from gc9a01/src/driver.rs
rename to vendor/gc9a01/src/driver.rs
diff --git a/gc9a01/src/lib.rs b/vendor/gc9a01/src/lib.rs
similarity index 100%
rename from gc9a01/src/lib.rs
rename to vendor/gc9a01/src/lib.rs
diff --git a/gc9a01/src/mode/basic.rs b/vendor/gc9a01/src/mode/basic.rs
similarity index 100%
rename from gc9a01/src/mode/basic.rs
rename to vendor/gc9a01/src/mode/basic.rs
diff --git a/gc9a01/src/mode/mod.rs b/vendor/gc9a01/src/mode/mod.rs
similarity index 100%
rename from gc9a01/src/mode/mod.rs
rename to vendor/gc9a01/src/mode/mod.rs
diff --git a/gc9a01/src/prelude.rs b/vendor/gc9a01/src/prelude.rs
similarity index 100%
rename from gc9a01/src/prelude.rs
rename to vendor/gc9a01/src/prelude.rs
diff --git a/gc9a01/src/rotation.rs b/vendor/gc9a01/src/rotation.rs
similarity index 100%
rename from gc9a01/src/rotation.rs
rename to vendor/gc9a01/src/rotation.rs
diff --git a/gc9a01/src/spi.rs b/vendor/gc9a01/src/spi.rs
similarity index 100%
rename from gc9a01/src/spi.rs
rename to vendor/gc9a01/src/spi.rs