diff --git a/src/controller.rs b/src/controller.rs
index 6ab2c7e..cb3d7b4 100644
--- a/src/controller.rs
+++ b/src/controller.rs
@@ -35,26 +35,21 @@ impl Controller {
         let inputs = self.inputs.read().unwrap();
         let lib = self.library.read().unwrap();
 
-        eprintln!("{}", termion::clear::All);
-        eprintln!("----------");
-        
         if inputs.active {
             eprintln!("(ACTIVE)");
         } else {
             eprintln!("(FROZEN)");
         }
 
-        if let Some(scene) = lib.get(inputs.scene_select) {
-            eprintln!("current animation: {}", scene.name());
-        }
-
         for si in 0..lib.len() {
             if let Some(scene) = lib.get(si) {
-                eprintln!("({}) {}", si, scene.name());
+                if si == inputs.scene_select {
+                    eprintln!(">> {}({}) {} {} <<", termion::style::Bold, si, termion::style::Reset, scene.name());
+                } else {
+                    eprintln!("    ({}) {} ", si, scene.name());
+                }
             }
         }
-
-        eprintln!("inputs:\n {:?}", inputs);
     }
 
     pub fn handle_key(
diff --git a/src/fixture.rs b/src/fixture.rs
index e8f83c5..c141805 100644
--- a/src/fixture.rs
+++ b/src/fixture.rs
@@ -2,12 +2,18 @@ use {
     prisma::{Rgb},
     cgmath::{Vector2},
     std::boxed::Box,
-    crate::view::ColorGrid
+    crate::{
+        view::ColorGrid,
+        fpsstat::{FpsStat}
+    }
 };
 
 pub trait FixtureDriver {
     fn send(&mut self, pixels: &Vec<Rgb<u8>>);
     fn sync(&mut self);
+
+    fn connect_info(&self) -> String;
+    fn avg_fps(&self) -> f32;
 }
 
 pub struct Fixture {
@@ -18,7 +24,7 @@ pub struct Fixture {
     pub mirror_y: bool,
     pub brightness: f32,
     pub buffer: Vec< Rgb<u8> >,
-    pub driver: Option<Box<dyn FixtureDriver>>
+    pub driver: Option<Box<dyn FixtureDriver>>,
 }
 
 impl Fixture {
diff --git a/src/fpsstat.rs b/src/fpsstat.rs
new file mode 100644
index 0000000..b2bc302
--- /dev/null
+++ b/src/fpsstat.rs
@@ -0,0 +1,30 @@
+
+use std::time::{Instant, Duration};
+
+pub struct FpsStat {
+    frame_count: u64,
+    fps_sum_window: std::time::Instant,
+    pub avg_fps: f32
+}
+
+impl FpsStat {
+    pub fn new() -> Self {
+        FpsStat {
+            frame_count: 0,
+            fps_sum_window: std::time::Instant::now(),
+            avg_fps: 0.0
+        }
+    }
+
+    pub fn refresh(&mut self) {
+        let tcur = std::time::Instant::now();
+        if (tcur - self.fps_sum_window).as_millis() > 5000 {
+            self.avg_fps = (1000.0 * self.frame_count as f32) / ((tcur - self.fps_sum_window).as_millis() as f32);
+
+            self.fps_sum_window = tcur;
+            self.frame_count = 0;
+        } else {
+            self.frame_count += 1;
+        }
+    }
+}
diff --git a/src/inputs.rs b/src/inputs.rs
index 2a28e99..e346749 100644
--- a/src/inputs.rs
+++ b/src/inputs.rs
@@ -46,4 +46,18 @@ impl Default for Inputs {
     }
 }
 
+impl Inputs {
+    pub fn display(&self) {
+        eprintln!("transition: {:?}", self.transition_time);
+        eprintln!("cycle: {:?}", self.cycle_len);
+        eprintln!("wave peak: {:?}", self.wave_peak);
+        eprintln!("master wave: {:?}", self.master_wave);
+        eprintln!("master subdivision: {}", self.master_subdivision);
+        eprintln!("master intensity: {}", self.master_intensity);
+        eprintln!("wheel 1: {}", self.wheel);
+        eprintln!("wheel 2: {}", self.wheel2);
+        eprintln!("wheel 3: {}", self.wheel3);
+    }
+}
+
 
diff --git a/src/main.rs b/src/main.rs
index c60f6fc..ace902d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,6 +22,7 @@ mod stripe_driver;
 mod jack;
 mod waveform;
 mod controller;
+mod fpsstat;
 
 mod patterns;
 mod scene_library;
@@ -82,8 +83,6 @@ async fn main() {
 
     let mut controller = controller::Controller::new( scene_library, inputs.clone() );
 
-    let mut frame_count = 0;
-    let mut fps_sum_window = std::time::Instant::now();
     {
     let inputs = controller.inputs.read().unwrap();
     lighting_setup.advance(&(*inputs) );
@@ -100,16 +99,6 @@ async fn main() {
                 tcur + Duration::from_millis(25)
             ));
 
-        // FPS statistics
-        if (tcur - fps_sum_window).as_millis() > 5000 {
-            let avg_fps = (1000.0 * frame_count as f32) / ((tcur - fps_sum_window).as_millis() as f32);
-            eprintln!("avg fps: {}", avg_fps);
-            fps_sum_window = tcur;
-            frame_count = 0;
-        } else {
-            frame_count += 1;
-        }
-
         // update animation
         let active = {
             let mut inputs = inputs.write().unwrap();
@@ -169,7 +158,14 @@ async fn main() {
                 controller.handle_key(
                     event, &mut lighting_setup
                 );
+
+                eprintln!("{}", termion::clear::All);
+                eprintln!("----------");
                 controller.display();
+                inputs.read().unwrap().display();
+                eprintln!("----------");
+                lighting_setup.display();
+                eprintln!("----------");                
             }
 
             _ => {}
diff --git a/src/setup.rs b/src/setup.rs
index 5f3f4f0..338dafe 100644
--- a/src/setup.rs
+++ b/src/setup.rs
@@ -2,18 +2,19 @@ use {
     crate::{
         fixture::Fixture,
         inputs::Inputs,
-        view::{ColorGrid, Animation}
+        view::{ColorGrid, Animation},
+        fpsstat::{FpsStat}
     },
     cgmath::Vector2,
     std::time::Duration,
-    std::sync::{Arc, RwLock}
+    std::sync::{Arc, RwLock},
 };
 
 pub struct LightingSetup {
     pub fixtures: Vec<Fixture>,
     t: Arc<RwLock<Duration>>,
-
-    animation: Arc<RwLock<dyn Animation>>
+    animation: Arc<RwLock<dyn Animation>>,
+    pub preview_fpsstat: RwLock<FpsStat>
 }
 
 impl LightingSetup {
@@ -22,7 +23,20 @@ impl LightingSetup {
         LightingSetup {
             fixtures,
             t: t.clone(),
-            animation
+            animation,
+            preview_fpsstat: RwLock::new(FpsStat::new())
+        }
+    }
+
+
+    pub fn display(&self) {
+        println!("preview: {} fps", self.preview_fpsstat.read().unwrap().avg_fps);
+        for (i,fixture) in self.fixtures.iter().enumerate() {
+            if let Some(driver) = fixture.driver.as_ref() {
+                println!("F{} . ({}) {}", i, driver.connect_info(), driver.avg_fps());
+            } else {
+                println!("disconnected");
+            }
         }
     }
 
@@ -59,6 +73,8 @@ impl LightingSetup {
         width: u32,
         height: u32
     ) {
+        self.preview_fpsstat.write().unwrap().refresh();
+
         // pixels per Unit
         let mindim = u32::min(width, height);
         let midx = width/2;
diff --git a/src/stripe_driver.rs b/src/stripe_driver.rs
index 81771a2..a6bc6fd 100644
--- a/src/stripe_driver.rs
+++ b/src/stripe_driver.rs
@@ -1,13 +1,17 @@
 use {
     prisma::{Rgb},
     std::sync::{Arc, RwLock},
-    crate::fixture::FixtureDriver
+    crate::{
+        fixture::FixtureDriver,
+        fpsstat::FpsStat
+    }
 };
 
 pub struct StripeDriver {
     socket: Arc<RwLock<std::net::UdpSocket>>,
     timeout: usize,
-    addr: String
+    addr: String,
+    pub fpsstat: FpsStat
 }
 
 impl StripeDriver {
@@ -15,7 +19,8 @@ impl StripeDriver {
         StripeDriver {
             addr: addr.into(),
             timeout: 0,
-            socket
+            socket,
+            fpsstat: FpsStat::new()
         }
     }
 }
@@ -33,6 +38,7 @@ impl FixtureDriver for StripeDriver {
             }
 
             self.socket.write().unwrap().send_to(&buf, &self.addr);
+            self.fpsstat.refresh();
 
             self.timeout = 100;
         } else {
@@ -43,5 +49,13 @@ impl FixtureDriver for StripeDriver {
     fn sync(&mut self) {
         self.timeout = 0;
     }
+
+    fn connect_info(&self) -> String {
+        format!("(timeout = {})", self.timeout)
+    }
+
+    fn avg_fps(&self) -> f32 {
+        self.fpsstat.avg_fps
+    }
 }