diff --git a/applications/gui/src/camera.cpp b/applications/gui/src/camera.cpp
index eedf63ffd5292edf71301bc2cbca63cbf1484d5c..f1682a06d90bf6dedf74631708b1e927262a8616 100644
--- a/applications/gui/src/camera.cpp
+++ b/applications/gui/src/camera.cpp
@@ -222,6 +222,7 @@ void ftl::gui::Camera::showSettings() {
 void ftl::gui::Camera::setChannel(ftl::rgbd::channel_t c) {
 	channel_ = c;
 	switch (c) {
+	case ftl::rgbd::kChanEnergy:
 	case ftl::rgbd::kChanFlow:
 	case ftl::rgbd::kChanConfidence:
 	case ftl::rgbd::kChanNormals:
@@ -255,6 +256,19 @@ static void visualizeDepthMap(	const cv::Mat &depth, cv::Mat &out,
 	out.setTo(cv::Scalar(255, 255, 255), mask);
 }
 
+static void visualizeEnergy(	const cv::Mat &depth, cv::Mat &out,
+								const float max_depth)
+{
+	DCHECK(max_depth > 0.0);
+
+	depth.convertTo(out, CV_8U, 255.0f / max_depth);
+	//out = 255 - out;
+	cv::Mat mask = (depth >= 39.0f); // TODO (mask for invalid pixels)
+	
+	applyColorMap(out, out, cv::COLORMAP_JET);
+	out.setTo(cv::Scalar(255, 255, 255), mask);
+}
+
 static void drawEdges(	const cv::Mat &in, cv::Mat &out,
 						const int ksize = 3, double weight = -1.0, const int threshold = 32,
 						const int threshold_type = cv::THRESH_TOZERO)
@@ -303,6 +317,11 @@ const GLTexture &ftl::gui::Camera::captureFrame() {
 		cv::Mat tmp;
 
 		switch(channel_) {
+			case ftl::rgbd::kChanEnergy:
+				if (depth.rows == 0) { break; }
+				visualizeEnergy(depth, tmp, 10.0);
+				texture_.update(tmp);
+				break;
 			case ftl::rgbd::kChanDepth:
 				if (depth.rows == 0) { break; }
 				visualizeDepthMap(depth, tmp, 7.0);
diff --git a/applications/gui/src/media_panel.cpp b/applications/gui/src/media_panel.cpp
index 6fb6d5085cc02efae38fcdfce0819ee0d2ae7110..44bb92ec099b5d961142ec4fc1fed95e200c7bd2 100644
--- a/applications/gui/src/media_panel.cpp
+++ b/applications/gui/src/media_panel.cpp
@@ -184,6 +184,15 @@ MediaPanel::MediaPanel(ftl::gui::Screen *screen) : nanogui::Window(screen, ""),
         }
     });
 
+    button = new Button(popup, "Energy");
+    button->setFlags(Button::RadioButton);
+    button->setCallback([this]() {
+        ftl::gui::Camera *cam = screen_->activeCamera();
+        if (cam) {
+            cam->setChannel(ftl::rgbd::kChanEnergy);
+        }
+    });
+
 }
 
 MediaPanel::~MediaPanel() {
diff --git a/applications/reconstruct/src/splat_render.cpp b/applications/reconstruct/src/splat_render.cpp
index aad8fb818215f1925ff0f159fc85d2b70b1d127d..df9d99a9f3b48dd59c2c7dd0b508a6a32aaded53 100644
--- a/applications/reconstruct/src/splat_render.cpp
+++ b/applications/reconstruct/src/splat_render.cpp
@@ -95,6 +95,16 @@ void Splatter::render(ftl::rgbd::Source *src, cudaStream_t stream) {
 				ftl::cuda::int_to_float(depth1_, depth2_, 1.0f / 1000.0f, stream);
 				src->writeFrames(colour1_, depth2_, stream);
 			}
+		} else if (src->getChannel() == ftl::rgbd::kChanEnergy) {
+			//ftl::cuda::int_to_float(depth1_, depth2_, 1.0f / 1000.0f, stream);
+			//if (src->value("splatting",  false)) {
+				//ftl::cuda::splat_points(depth1_, colour1_, normal1_, depth2_, colour2_, params, stream);
+				//ftl::cuda::int_to_float(depth1_, depth2_, 1.0f / 1000.0f, stream);
+				src->writeFrames(colour1_, depth2_, stream);
+			//} else {
+				//ftl::cuda::int_to_float(depth1_, depth2_, 1.0f / 1000.0f, stream);
+			//	src->writeFrames(colour1_, depth2_, stream);
+			//}
 		} else if (src->getChannel() == ftl::rgbd::kChanRight) {
 			// Adjust pose to right eye position
 			Eigen::Affine3f transform(Eigen::Translation3f(camera.baseline,0.0f,0.0f));
diff --git a/components/rgbd-sources/include/ftl/rgbd/detail/source.hpp b/components/rgbd-sources/include/ftl/rgbd/detail/source.hpp
index b76dd27fac1a7f09a07612629c9d6aae8ef47eb3..dcde8047ee902990dad4e03c550cd0f48a8480aa 100644
--- a/components/rgbd-sources/include/ftl/rgbd/detail/source.hpp
+++ b/components/rgbd-sources/include/ftl/rgbd/detail/source.hpp
@@ -21,11 +21,12 @@ static const channel_t kChanDeviation = 0x0010;
 static const channel_t kChanNormals = 0x0020;
 static const channel_t kChanConfidence = 0x0040;
 static const channel_t kChanFlow = 0x0080;
+static const channel_t kChanEnergy = 0x0100;
 
 static const channel_t kChanOverlay1 = 0x1000;
 
 inline bool isFloatChannel(ftl::rgbd::channel_t chan) {
-	return (chan == ftl::rgbd::kChanDepth);
+	return (chan == ftl::rgbd::kChanDepth || chan == ftl::rgbd::kChanEnergy);
 }
 
 
diff --git a/components/rgbd-sources/src/streamer.cpp b/components/rgbd-sources/src/streamer.cpp
index 21821c908964b5f0889330fa931888c9bc10bcf1..e52e20e394bca414e7b2a08e8c628481cf2fe1a0 100644
--- a/components/rgbd-sources/src/streamer.cpp
+++ b/components/rgbd-sources/src/streamer.cpp
@@ -101,6 +101,8 @@ Streamer::Streamer(nlohmann::json &config, Universe *net)
 	net->bind("set_channel", [this](const string &uri, unsigned int chan) {
 		SHARED_LOCK(mutex_,slk);
 
+		LOG(INFO) << "SET CHANNEL " << chan;
+
 		if (sources_.find(uri) != sources_.end()) {
 			sources_[uri]->src->setChannel((ftl::rgbd::channel_t)chan);
 		}