diff --git a/Cargo.lock b/Cargo.lock
index 6ad4f06a..5ca2cf2b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -268,6 +268,15 @@ version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "53857514f72ee4a2b583de67401e3ff63a5472ca4acf289d09a9ea7636dfec17"
 
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
+dependencies = [
+ "crossbeam-utils",
+]
+
 [[package]]
 name = "crossbeam-deque"
 version = "0.8.6"
@@ -318,6 +327,16 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "ctor"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
+dependencies = [
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "darling"
 version = "0.20.10"
@@ -543,7 +562,10 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 name = "jack"
 version = "0.13.0"
 dependencies = [
+ "approx",
  "bitflags 2.6.0",
+ "crossbeam-channel",
+ "ctor",
  "jack-sys",
  "lazy_static",
  "libc",
@@ -1436,6 +1458,7 @@ dependencies = [
  "clojure-reader",
  "itertools 0.14.0",
  "konst",
+ "tek_tui",
 ]
 
 [[package]]
@@ -1466,6 +1489,7 @@ name = "tek_output"
 version = "0.2.0"
 dependencies = [
  "tek_edn",
+ "tek_tui",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 2c4a04a1..1cb93658 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,12 +1,13 @@
-[package]
-name = "tek_cli"
-edition = "2021"
-version = "0.2.0"
-
-[dependencies]
-tek = { path = "./tek" }
-clap = { version = "4.5.4", features = [ "derive" ] }
-
-[[bin]]
-name = "tek"
-path = "./tek.rs"
+[workspace]
+resolver = "2"
+members = [
+  "./cli",
+  "./edn",
+  "./input",
+  "./jack",
+  "./midi",
+  "./output",
+  "./tek",
+  "./time",
+  "./tui"
+]
diff --git a/Justfile b/Justfile
index 77701a20..86ea048e 100644
--- a/Justfile
+++ b/Justfile
@@ -1,5 +1,5 @@
 default:
-  just -l
+  bacon -sj test
 
 status:
   cargo c
@@ -19,59 +19,55 @@ fpush:
 ftpush:
   git push --tags -fu codeberg && git push --tags -fu origin
 
+debug    := "reset && cargo run --"
+release  := "reset && cargo run --release --"
+name     := "-n tek"
+bpm      := "-b 174"
+midi-in  := "-i '.*nanoKey.*capture.*'"
+midi-out := "-o '.*Komplete.*playback.*MIDI*'"
+
+# TODO: arranger track mappings
+#-i "1=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _"
+#-o "1=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
+#-i "2=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _"
+#-o "2=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
+#-i "3=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _"
+#-o "3=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
+#-i "4=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _"
+#-o "4=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
+
 run:
-  reset && cargo run
+  {{debug}}
+release:
+  {{release}}
 
 clock:
-  reset && cargo run -- clock
+  {{debug}} {{name}} {{bpm}} clock
 clock-release:
-  reset && cargo run --release -- clock
+  {{release}} {{name}} {{bpm}} clock
 
 arranger:
-  reset && cargo run --bin tek -- arranger
+  {{debug}} {{name}} {{bpm}} arranger
 arranger-ext:
-  reset && cargo run --bin tek -- arranger -n tek \
-    -i "1=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "1=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-    -i "2=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "2=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-    -i "3=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "3=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-    -i "4=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "4=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
+  {{debug}} {{name}} {{bpm}} {{midi-in}} {{midi-out}} arranger
 arranger-release:
-  reset
-  cargo run --release -- arranger
+  {{release}} {{name}} {{bpm}} arranger
 arranger-release-ext:
-  reset
-  cargo run --release -- arranger -n tek \
-    -i "1=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "1=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-    -i "2=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "2=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-    -i "3=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "3=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-    -i "4=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "4=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
+  {{release}} {{name}} {{bpm}} {{midi-in}} {{midi-out}} arranger
 
 groovebox:
-  reset
-  cargo run -- -n tek -b 174 groovebox
+  {{debug}} {{name}} {{bpm}} groovebox
 groovebox-ext:
   reset
-  cargo run -- -n tek -b 174 groovebox \
-    -i "Midi-Bridge:nanoKEY Studio.*capture.*" \
+  {{debug}} {{name}} {{bpm}} {{midi-in}} {{midi-out}} groovebox \
     -l "Komplete Audio 6 Pro:capture_AUX1" \
     -r "Komplete Audio 6 Pro:capture_AUX1" \
     -L "Komplete Audio 6 Pro:playback_AUX1" \
     -R "Komplete Audio 6 Pro:playback_AUX1"
 groovebox-release:
-  reset
-  cargo run --release -- -n tek -b 174 groovebox
+  {{release}} {{name}} {{bpm}} groovebox
 groovebox-release-ext:
-  reset
-  cargo run --release -- -n tek -b 174 groovebox \
-    -i "Midi-Bridge:nanoKEY Studio.*capture.*" \
+  {{release}} {{name}} {{bpm}} {{midi-in}} {{midi-out}} groovebox \
     -l "Komplete Audio 6 Pro:capture_AUX1" \
     -r "Komplete Audio 6 Pro:capture_AUX1" \
     -L "Komplete Audio 6 Pro:playback_AUX1" \
@@ -87,28 +83,22 @@ groovebox-release-ext-browser:
     -R "Komplete Audio 6 Pro:playback_AUX2"
 
 sequencer:
-  reset
-  cargo run -- sequencer
+  {{debug}} {{name}} {{bpm}} sequencer
 sequencer-ext:
-  reset
-  cargo run -- sequencer \
-    -i "Midi-Bridge:nanoKEY Studio 1:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "Midi-Bridge:Komplete Audio 6 0:(playback_0) Komplete Audio 6 MIDI 1"
+  {{debug}} {{name}} {{bpm}} {{midi-in}} {{midi-out}} sequencer
 sequencer-release:
-  reset cargo run --release -- sequencer
+  {{release}} {{name}} {{bpm}} sequencer
 sequencer-release-ext:
-  reset && cargo run --release -- sequencer \
-    -i "Midi-Bridge:nanoKEY Studio 1:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-    -o "Midi-Bridge:Komplete Audio 6 0:(playback_0) Komplete Audio 6 MIDI 1"
+  {{release}} {{name}} {{bpm}} {{midi-in}} {{midi-out}} sequencer
 
 mixer:
-  reset && cargo run -- mixer
+  {{debug}} mixer
 track:
-  reset && cargo run -- track
+  {{debug}} track
 sampler:
-  reset && cargo run -- sampler
+  {{debug}} sampler
 plugin:
-  reset && cargo run -- plugin
+  {{debug}} plugin
 
 edn:
   reset
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
new file mode 100644
index 00000000..6f5b82e8
--- /dev/null
+++ b/cli/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "tek_cli"
+edition = "2021"
+version = "0.2.0"
+
+[dependencies]
+tek = { path = "../tek" }
+clap = { version = "4.5.4", features = [ "derive" ] }
+
+[[bin]]
+name = "tek"
+path = "./tek.rs"
diff --git a/cli/tek.rs b/cli/tek.rs
new file mode 100644
index 00000000..1f41cb77
--- /dev/null
+++ b/cli/tek.rs
@@ -0,0 +1,175 @@
+use std::sync::{Arc, RwLock};
+use tek::*;
+#[allow(unused_imports)] use clap::{self, Parser, Subcommand, ValueEnum};
+
+#[derive(Debug, Parser)]
+#[command(version, about, long_about = None)]
+pub struct TekCli {
+    /// Which app to initialize
+    #[command(subcommand)] mode: TekMode,
+    /// Name of JACK client
+    #[arg(short='n', long)] name: Option<String>,
+    /// Whether to attempt to become transport master
+    #[arg(short='S', long, default_value_t = false)] sync_lead: bool,
+    /// Whether to sync to external transport master
+    #[arg(short='s', long, default_value_t = true)] sync_follow: bool,
+    /// Initial tempo in beats per minute
+    #[arg(short='b', long, default_value = None)] bpm: Option<f64>,
+    /// Whether to include a transport toolbar (default: true)
+    #[arg(short='t', long, default_value_t = true)] show_clock: bool,
+    /// MIDI outs to connect to (multiple instances accepted)
+    #[arg(short='I', long)] midi_from: Vec<String>,
+    /// MIDI outs to connect to (multiple instances accepted)
+    #[arg(short='i', long)] midi_from_re: Vec<String>,
+    /// MIDI ins to connect to (multiple instances accepted)
+    #[arg(short='O', long)] midi_to: Vec<String>,
+    /// MIDI ins to connect to (multiple instances accepted)
+    #[arg(short='o', long)] midi_to_re: Vec<String>,
+    /// Audio outs to connect to left input
+    #[arg(short='l', long)] left_from: Vec<String>,
+    /// Audio outs to connect to right input
+    #[arg(short='r', long)] right_from: Vec<String>,
+    /// Audio ins to connect from left output
+    #[arg(short='L', long)] left_to: Vec<String>,
+    /// Audio ins to connect from right output
+    #[arg(short='R', long)] right_to: Vec<String>,
+}
+
+#[derive(Debug, Clone, Subcommand)]
+pub enum TekMode {
+    /// A standalone transport clock.
+    Clock,
+    /// A MIDI sequencer.
+    Sequencer,
+    /// A MIDI-controlled audio sampler.
+    Sampler,
+    /// Sequencer and sampler together.
+    Groovebox,
+    /// Multi-track MIDI sequencer.
+    Arranger {
+        /// Number of tracks
+        #[arg(short = 'x', long, default_value_t = 16)] tracks:      usize,
+        /// Width of tracks
+        #[arg(short = 'w', long, default_value_t = 6)]  track_width: usize,
+        /// Number of scenes
+        #[arg(short = 'y', long, default_value_t = 8)]  scenes:      usize,
+    },
+    /// TODO: A MIDI-controlled audio mixer
+    Mixer,
+    /// TODO: A customizable channel strip
+    Track,
+    /// TODO: An audio plugin host
+    Plugin,
+}
+
+/// Application entrypoint.
+pub fn main () -> Usually<()> {
+    let cli         = TekCli::parse();
+    let name        = cli.name.as_ref().map_or("tek", |x|x.as_str());
+    let jack        = JackConnection::new(name)?;
+    let engine      = Tui::new()?;
+    let empty       = &[] as &[&str];
+    let midi_froms  = PortConnection::collect(&cli.midi_from,  &cli.midi_from_re, empty);
+    let midi_tos    = PortConnection::collect(&cli.midi_to,    &cli.midi_to_re,   empty);
+    let left_froms  = PortConnection::collect(&cli.left_from,  empty, empty);
+    let left_tos    = PortConnection::collect(&cli.left_to,    empty, empty);
+    let right_froms = PortConnection::collect(&cli.right_from, empty, empty);
+    let right_tos   = PortConnection::collect(&cli.right_to,   empty, empty);
+    Ok(match cli.mode {
+
+        TekMode::Clock => engine.run(&jack.activate_with(|jack|Ok(TransportTui {
+            clock: Clock::from(jack),
+            jack:  jack.clone()
+        }))?)?,
+
+        TekMode::Sequencer => engine.run(&jack.activate_with(|jack|Ok({
+            let length = 384;
+            let color  = Some(ItemColor::random().into());
+            let clip   = Arc::new(RwLock::new(MidiClip::new("Clip", true, length, None, color)));
+            let player = MidiPlayer::new(&jack, name, Some(&clip), &midi_froms, &midi_tos)?;
+            Sequencer {
+                _jack:     jack.clone(),
+                clock:     player.clock.clone(),
+                player,
+                editor:    MidiEditor::from(&clip),
+                pool:      PoolModel::from(&clip),
+                compact:   true,
+                transport: true,
+                selectors: true,
+                size:      Measure::new(),
+                midi_buf:  vec![vec![];65536],
+                note_buf:  vec![],
+                perf:      PerfModel::default(),
+                status:    true,
+            }
+        }))?)?,
+
+        TekMode::Sampler => engine.run(&jack.activate_with(|jack|Ok(
+            SamplerTui {
+                cursor:  (0, 0),
+                editing: None,
+                mode:    None,
+                size:    Measure::new(),
+                note_lo: 36.into(),
+                note_pt: 36.into(),
+                color:   ItemPalette::from(Color::Rgb(64, 128, 32)),
+                state:   Sampler::new(jack, &"sampler", &midi_froms,
+                    &[&left_froms, &right_froms], &[&left_tos, &right_tos])?,
+            }
+        ))?)?,
+
+        TekMode::Groovebox => engine.run(&jack.activate_with(|jack|Ok({
+            let length  = 384;
+            let color   = Some(ItemColor::random().into());
+            let clip    = Arc::new(RwLock::new(MidiClip::new("Clip", true, length, None, color)));
+            let player  = MidiPlayer::new(jack, &"sequencer", Some(&clip), &midi_froms, &midi_tos)?;
+            let sampler = Sampler::new(jack, &"sampler", &midi_froms,
+                &[&left_froms, &right_froms], &[&left_tos, &right_tos])?;
+            jack.read().unwrap().client().connect_ports(&player.midi_outs[0].port, &sampler.midi_in.port)?;
+            let app = Groovebox {
+                player,
+                sampler,
+                pool:     PoolModel::from(&clip),
+                editor:   MidiEditor::from(&clip),
+                compact:  true,
+                status:   true,
+                size:     Measure::new(),
+                midi_buf: vec![vec![];65536],
+                note_buf: vec![],
+                perf:     PerfModel::default(),
+                _jack:    jack.clone(),
+            };
+            if let Some(bpm) = cli.bpm {
+                app.clock().timebase.bpm.set(bpm);
+            }
+            if cli.sync_lead {
+                jack.read().unwrap().client().register_timebase_callback(false, |mut state|{
+                    app.clock().playhead.update_from_sample(state.position.frame() as f64);
+                    state.position.bbt = Some(app.clock().bbt());
+                    state.position
+                })?
+            } else if cli.sync_follow {
+                jack.read().unwrap().client().register_timebase_callback(false, |state|{
+                    app.clock().playhead.update_from_sample(state.position.frame() as f64);
+                    state.position
+                })?
+            }
+            app
+        }))?)?,
+
+        TekMode::Arranger { scenes, tracks, track_width, .. } =>
+            engine.run(&jack.activate_with(|jack|Ok({
+                let mut app = Arranger::new(jack);
+                app.tracks_add(tracks, track_width, &midi_froms, &midi_tos)?;
+                app.scenes_add(scenes)?;
+                app
+            }))?)?,
+
+        _ => todo!()
+    })
+}
+
+#[test] fn verify_cli () {
+    use clap::CommandFactory;
+    TekCli::command().debug_assert();
+}
diff --git a/edn/src/lib.rs b/edn/src/lib.rs
index 90f6fcd9..114fd675 100644
--- a/edn/src/lib.rs
+++ b/edn/src/lib.rs
@@ -30,8 +30,8 @@ mod edn_token; pub use self::edn_token::*;
 }
 
 #[cfg(test)] #[test] fn test_edn_layout () -> Result<(), ParseError> {
-    EdnItem::<String>::read_all(include_str!("../examples/edn01.edn"))?;
-    EdnItem::<String>::read_all(include_str!("../examples/edn02.edn"))?;
+    EdnItem::<String>::read_all(include_str!("../tek/examples/edn01.edn"))?;
+    EdnItem::<String>::read_all(include_str!("../tek/examples/edn02.edn"))?;
     //panic!("{layout:?}");
     //let content = <dyn EdnViewData<::tek_engine::tui::Tui>>::from(&layout);
     Ok(())
diff --git a/input/src/lib.rs b/input/src/lib.rs
index fba57784..b9798d08 100644
--- a/input/src/lib.rs
+++ b/input/src/lib.rs
@@ -21,6 +21,7 @@ pub(crate) type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
 }
 
 #[cfg(test)] #[test] fn test_stub_engine () -> Usually<()> {
+    use crate::*;
     struct TestEngine(bool);
     struct TestInput(bool);
     struct TestOutput([u16;4]);
diff --git a/shell.nix b/shell.nix
index cd5d101c..78aa3b99 100755
--- a/shell.nix
+++ b/shell.nix
@@ -1,10 +1,8 @@
 #!/usr/bin/env nix-shell
 {pkgs?import<nixpkgs>{}}:let
-
   #suil = pkgs.enableDebugging (pkgs.suil.overrideAttrs (a: b: {
     #dontStrip = true; separateDebugInfo = true;
   #}));
-
 in pkgs.mkShell {
   nativeBuildInputs = with pkgs; [
     pkg-config
diff --git a/tek.rs b/tek.rs
index be256efc..e69de29b 100644
--- a/tek.rs
+++ b/tek.rs
@@ -1,175 +0,0 @@
-use std::sync::{Arc, RwLock};
-use tek::*;
-#[allow(unused_imports)] use clap::{self, Parser, Subcommand, ValueEnum};
-
-#[derive(Debug, Parser)]
-#[command(version, about, long_about = None)]
-pub struct TekCli {
-    /// Which app to initialize
-    #[command(subcommand)] mode: TekMode,
-    /// Name of JACK client
-    #[arg(short='n', long)] name: Option<String>,
-    /// Whether to attempt to become transport master
-    #[arg(short='S', long, default_value_t = false)] sync_lead: bool,
-    /// Whether to sync to external transport master
-    #[arg(short='s', long, default_value_t = true)] sync_follow: bool,
-    /// Initial tempo in beats per minute
-    #[arg(short='b', long, default_value = None)] bpm: Option<f64>,
-    /// Whether to include a transport toolbar (default: true)
-    #[arg(short='t', long, default_value_t = true)] show_clock: bool,
-    /// MIDI outs to connect to (multiple instances accepted)
-    #[arg(short='I', long)] midi_from: Vec<String>,
-    /// MIDI outs to connect to (multiple instances accepted)
-    #[arg(short='i', long)] midi_from_re: Vec<String>,
-    /// MIDI ins to connect to (multiple instances accepted)
-    #[arg(short='O', long)] midi_to: Vec<String>,
-    /// MIDI ins to connect to (multiple instances accepted)
-    #[arg(short='o', long)] midi_to_re: Vec<String>,
-    /// Audio outs to connect to left input
-    #[arg(short='l', long)] left_from: Vec<String>,
-    /// Audio outs to connect to right input
-    #[arg(short='r', long)] right_from: Vec<String>,
-    /// Audio ins to connect from left output
-    #[arg(short='L', long)] left_to: Vec<String>,
-    /// Audio ins to connect from right output
-    #[arg(short='R', long)] right_to: Vec<String>,
-}
-
-#[derive(Debug, Clone, Subcommand)]
-pub enum TekMode {
-    /// A standalone transport clock.
-    Clock,
-    /// A MIDI sequencer.
-    Sequencer,
-    /// A MIDI-controlled audio sampler.
-    Sampler,
-    /// Sequencer and sampler together.
-    Groovebox,
-    /// Multi-track MIDI sequencer.
-    Arranger {
-        /// Number of tracks
-        #[arg(short = 'x', long, default_value_t = 16)] tracks:      usize,
-        /// Width of tracks
-        #[arg(short = 'w', long, default_value_t = 6)]  track_width: usize,
-        /// Number of scenes
-        #[arg(short = 'y', long, default_value_t = 8)]  scenes:      usize,
-    },
-    /// TODO: A MIDI-controlled audio mixer
-    Mixer,
-    /// TODO: A customizable channel strip
-    Track,
-    /// TODO: An audio plugin host
-    Plugin,
-}
-
-/// Application entrypoint.
-pub fn main () -> Usually<()> {
-    let cli         = TekCli::parse();
-    let name        = cli.name.as_ref().map_or("tek", |x|x.as_str());
-    let jack        = JackConnection::new(name)?;
-    let engine      = Tui::new()?;
-    let empty       = &[] as &[&str];
-    let midi_froms  = PortConnection::collect(&cli.midi_from,  &cli.midi_from_re, empty);
-    let midi_tos    = PortConnection::collect(&cli.midi_to,    &cli.midi_to_re,   empty);
-    let left_froms  = PortConnection::collect(&cli.left_from,  empty, empty);
-    let left_tos    = PortConnection::collect(&cli.left_to,    empty, empty);
-    let right_froms = PortConnection::collect(&cli.right_from, empty, empty);
-    let right_tos   = PortConnection::collect(&cli.right_to,   empty, empty);
-    Ok(match cli.mode {
-
-        TekMode::Clock => engine.run(&jack.activate_with(|jack|Ok(TransportTui {
-            clock: Clock::from(jack),
-            jack:  jack.clone()
-        }))?)?,
-
-        TekMode::Sequencer => engine.run(&jack.activate_with(|jack|Ok({
-            let length = 384;
-            let color  = Some(ItemColor::random().into());
-            let clip   = Arc::new(RwLock::new(MidiClip::new("Clip", true, length, None, color)));
-            let player = MidiPlayer::new(&jack, name, Some(&clip), &midi_froms, &midi_tos)?;
-            Sequencer {
-                _jack:     jack.clone(),
-                clock:     player.clock.clone(),
-                player,
-                editor:    MidiEditor::from(&clip),
-                pool:      PoolModel::from(&clip),
-                compact:   true,
-                transport: true,
-                selectors: true,
-                size:      Measure::new(),
-                midi_buf:  vec![vec![];65536],
-                note_buf:  vec![],
-                perf:      PerfModel::default(),
-                status:    true,
-            }
-        }))?)?,
-
-        TekMode::Sampler => engine.run(&jack.activate_with(|jack|Ok(
-            SamplerTui {
-                cursor:  (0, 0),
-                editing: None,
-                mode:    None,
-                size:    Measure::new(),
-                note_lo: 36.into(),
-                note_pt: 36.into(),
-                color:   ItemPalette::from(Color::Rgb(64, 128, 32)),
-                state:   Sampler::new(jack, &"sampler", &midi_froms,
-                    &[&left_froms, &right_froms], &[&left_tos, &right_tos])?,
-            }
-        ))?)?,
-
-        TekMode::Groovebox => engine.run(&jack.activate_with(|jack|Ok({
-            let length = 384;
-            let color  = Some(ItemColor::random().into());
-            let clip   = Arc::new(RwLock::new(MidiClip::new("Clip", true, length, None, color)));
-            let mut player = MidiPlayer::new(jack, &"sequencer", Some(&clip), &midi_froms, &midi_tos)?;
-            let sampler = Sampler::new(jack, &"sampler", &midi_froms,
-                &[&left_froms, &right_froms], &[&left_tos, &right_tos])?;
-            jack.read().unwrap().client().connect_ports(&player.midi_outs[0].port, &sampler.midi_in.port)?;
-            let app = Groovebox {
-                player,
-                sampler,
-                pool:     PoolModel::from(&clip),
-                editor:   MidiEditor::from(&clip),
-                compact:  true,
-                status:   true,
-                size:     Measure::new(),
-                midi_buf: vec![vec![];65536],
-                note_buf: vec![],
-                perf:     PerfModel::default(),
-                _jack:    jack.clone(),
-            };
-            if let Some(bpm) = cli.bpm {
-                app.clock().timebase.bpm.set(bpm);
-            }
-            if cli.sync_lead {
-                jack.read().unwrap().client().register_timebase_callback(false, |mut state|{
-                    app.clock().playhead.update_from_sample(state.position.frame() as f64);
-                    state.position.bbt = Some(app.clock().bbt());
-                    state.position
-                })?
-            } else if cli.sync_follow {
-                jack.read().unwrap().client().register_timebase_callback(false, |state|{
-                    app.clock().playhead.update_from_sample(state.position.frame() as f64);
-                    state.position
-                })?
-            }
-            app
-        }))?)?,
-
-        TekMode::Arranger { scenes, tracks, track_width, .. } =>
-            engine.run(&jack.activate_with(|jack|Ok({
-                let mut app = Arranger::new(jack);
-                app.tracks_add(tracks, track_width, &midi_froms, &midi_tos)?;
-                app.scenes_add(scenes)?;
-                app
-            }))?)?,
-
-        _ => todo!()
-    })
-}
-
-#[test] fn verify_cli () {
-    use clap::CommandFactory;
-    TekCli::command().debug_assert();
-}
diff --git a/examples/demo.rs.fixme b/tek/examples/demo.rs.fixme
similarity index 100%
rename from examples/demo.rs.fixme
rename to tek/examples/demo.rs.fixme
diff --git a/examples/edn.rs b/tek/examples/edn.rs
similarity index 96%
rename from examples/edn.rs
rename to tek/examples/edn.rs
index 62ef8bb2..f6188dcf 100644
--- a/examples/edn.rs
+++ b/tek/examples/edn.rs
@@ -1,4 +1,4 @@
-use tek_tui::{*, tek_layout::{*, tek_engine::*}};
+use tek::*;
 use tek_edn::*;
 use std::sync::{Arc, RwLock};
 use crossterm::event::{*, KeyCode::*};
diff --git a/examples/edn01.edn b/tek/examples/edn01.edn
similarity index 100%
rename from examples/edn01.edn
rename to tek/examples/edn01.edn
diff --git a/examples/edn02.edn b/tek/examples/edn02.edn
similarity index 100%
rename from examples/edn02.edn
rename to tek/examples/edn02.edn
diff --git a/examples/edn03.edn b/tek/examples/edn03.edn
similarity index 100%
rename from examples/edn03.edn
rename to tek/examples/edn03.edn
diff --git a/examples/edn99.edn b/tek/examples/edn99.edn
similarity index 100%
rename from examples/edn99.edn
rename to tek/examples/edn99.edn
diff --git a/examples/midi_import.rs.fixme b/tek/examples/midi_import.rs.fixme
similarity index 100%
rename from examples/midi_import.rs.fixme
rename to tek/examples/midi_import.rs.fixme
diff --git a/examples/mixer.edn b/tek/examples/mixer.edn
similarity index 100%
rename from examples/mixer.edn
rename to tek/examples/mixer.edn
diff --git a/examples/sequencer.edn b/tek/examples/sequencer.edn
similarity index 100%
rename from examples/sequencer.edn
rename to tek/examples/sequencer.edn
diff --git a/tui/src/lib.rs b/tui/src/lib.rs
index bc68ac92..db1dce5c 100644
--- a/tui/src/lib.rs
+++ b/tui/src/lib.rs
@@ -89,7 +89,7 @@ pub(crate) use ratatui::{
 
 
 #[cfg(test)] #[test] fn test_tui_engine () -> Usually<()> {
-    use crate::tui::*;
+    use crate::*;
     use std::sync::{Arc, RwLock};
     struct TestComponent(String);
     impl Content<TuiOut> for TestComponent {