diff --git a/applications/reconstruct/include/ftl/voxel_hash_params.hpp b/applications/reconstruct/include/ftl/voxel_hash_params.hpp
index 480e16d478a7a3c82d046f6de464d7bb20c04f64..5e13ec21c259eec02d9a2f49b25ad3a98c06d08c 100644
--- a/applications/reconstruct/include/ftl/voxel_hash_params.hpp
+++ b/applications/reconstruct/include/ftl/voxel_hash_params.hpp
@@ -28,8 +28,8 @@ struct __align__(16) HashParams {
 	unsigned int	m_integrationWeightSample;
 	unsigned int	m_integrationWeightMax;
 
-	int3 m_minBounds;
-	int3 m_maxBounds;
+	float3 m_minBounds;
+	float3 m_maxBounds;
 	float m_spatialSmoothing;
 	float m_colourSmoothing;
 	float m_confidenceThresh;
diff --git a/applications/reconstruct/src/voxel_scene.cpp b/applications/reconstruct/src/voxel_scene.cpp
index 5d392d4f74f010c25fc52da3bc0f6936fc15efce..2dca323166936658a14870606a036baf80991b89 100644
--- a/applications/reconstruct/src/voxel_scene.cpp
+++ b/applications/reconstruct/src/voxel_scene.cpp
@@ -295,14 +295,14 @@ HashParams SceneRep::_parametersFromConfig() {
 	params.m_flags = 0;
 	params.m_flags |= (value("clipping", false)) ? ftl::voxhash::kFlagClipping : 0;
 	params.m_flags |= (value("mls", false)) ? ftl::voxhash::kFlagMLS : 0;
-	params.m_maxBounds = make_int3(
-		value("bbox_x_max", 2.0f) / (params.m_virtualVoxelSize*SDF_BLOCK_SIZE),
-		value("bbox_y_max", 2.0f) / (params.m_virtualVoxelSize*SDF_BLOCK_SIZE),
-		value("bbox_z_max", 2.0f) / (params.m_virtualVoxelSize*SDF_BLOCK_SIZE));
-	params.m_minBounds = make_int3(
-		value("bbox_x_min", -2.0f) / (params.m_virtualVoxelSize*SDF_BLOCK_SIZE),
-		value("bbox_y_min", -2.0f) / (params.m_virtualVoxelSize*SDF_BLOCK_SIZE),
-		value("bbox_z_min", -2.0f) / (params.m_virtualVoxelSize*SDF_BLOCK_SIZE));
+	params.m_maxBounds = make_float3(
+		value("bbox_x_max", 2.0f),
+		value("bbox_y_max", 2.0f),
+		value("bbox_z_max", 2.0f));
+	params.m_minBounds = make_float3(
+		value("bbox_x_min", -2.0f),
+		value("bbox_y_min", -2.0f),
+		value("bbox_z_min", -2.0f));
 	return params;
 }
 
diff --git a/components/rgbd-sources/include/ftl/rgbd/streamer.hpp b/components/rgbd-sources/include/ftl/rgbd/streamer.hpp
index d2beacb2105c38dfa7d3c8317f2e6512cb07c570..82dba747857eb0c6fc7ab62e52990f3e2a30ae67 100644
--- a/components/rgbd-sources/include/ftl/rgbd/streamer.hpp
+++ b/components/rgbd-sources/include/ftl/rgbd/streamer.hpp
@@ -35,7 +35,7 @@ static const unsigned int kFrameDropLimit = 5;
 
 struct StreamSource {
 	ftl::rgbd::Source *src;
-	std::atomic<unsigned int> jobs;				// Busy or ready to swap?
+	std::atomic<int> jobs;				// Busy or ready to swap?
 	std::atomic<unsigned int> clientCount;
 	cv::Mat rgb;									// Tx buffer
 	cv::Mat depth;									// Tx buffer
diff --git a/components/rgbd-sources/src/source.cpp b/components/rgbd-sources/src/source.cpp
index 9aee6dfbdbbcbec518ed3c3da879c7aa346c3096..913fe4acb53afb28b63c6e89d97e50dca6a669b6 100644
--- a/components/rgbd-sources/src/source.cpp
+++ b/components/rgbd-sources/src/source.cpp
@@ -165,10 +165,10 @@ ftl::rgbd::detail::Source *Source::_createDeviceImpl(const ftl::URI &uri) {
 
 void Source::getFrames(cv::Mat &rgb, cv::Mat &depth) {
 	SHARED_LOCK(mutex_,lk);
-	//rgb_.copyTo(rgb);
-	//depth_.copyTo(depth);
-	rgb = rgb_;
-	depth = depth_;
+	rgb_.copyTo(rgb);
+	depth_.copyTo(depth);
+	//rgb = rgb_;
+	//depth = depth_;
 
 	/*cv::Mat tmp;
 	tmp = rgb;
@@ -244,7 +244,7 @@ bool Source::compute(int N, int B) {
 		return true;
 	} else if (impl_ && impl_->compute(N,B)) {
 		timestamp_ = impl_->timestamp_;
-		/*cv::Mat tmp;
+		cv::Mat tmp;
 		rgb_.create(impl_->rgb_.size(), impl_->rgb_.type());
 		depth_.create(impl_->depth_.size(), impl_->depth_.type());
 		tmp = rgb_;
@@ -252,10 +252,10 @@ bool Source::compute(int N, int B) {
 		impl_->rgb_ = tmp;
 		tmp = depth_;
 		depth_ = impl_->depth_;
-		impl_->depth_ = tmp;*/
+		impl_->depth_ = tmp;
 
-		impl_->rgb_.copyTo(rgb_);
-		impl_->depth_.copyTo(depth_);
+		//impl_->rgb_.copyTo(rgb_);
+		//impl_->depth_.copyTo(depth_);
 		return true;
 	}
 	return false;
diff --git a/components/rgbd-sources/src/streamer.cpp b/components/rgbd-sources/src/streamer.cpp
index ab03f2a6527163d3413e7a1d2ada8aed9803f07f..21821c908964b5f0889330fa931888c9bc10bcf1 100644
--- a/components/rgbd-sources/src/streamer.cpp
+++ b/components/rgbd-sources/src/streamer.cpp
@@ -263,30 +263,31 @@ void Streamer::run(bool block) {
 void Streamer::_swap(StreamSource *src) {
 	if (src->jobs == 0) {
 		UNIQUE_LOCK(src->mutex,lk);
-
-		for (unsigned int b=0; b<10; ++b) {
-			auto i = src->clients[b].begin();
-			while (i != src->clients[b].end()) {
-				// Client request completed so remove from list
-				if ((*i).txcount >= (*i).txmax) {
-					LOG(INFO) << "Remove client: " << (*i).uri;
-					i = src->clients[b].erase(i);
-					--src->clientCount;
-				} else {
-					i++;
+		if (src->jobs == 0) {
+			for (unsigned int b=0; b<10; ++b) {
+				auto i = src->clients[b].begin();
+				while (i != src->clients[b].end()) {
+					// Client request completed so remove from list
+					if ((*i).txcount >= (*i).txmax) {
+						LOG(INFO) << "Remove client: " << (*i).uri;
+						i = src->clients[b].erase(i);
+						--src->clientCount;
+					} else {
+						i++;
+					}
 				}
 			}
-		}
 
-		src->src->getFrames(src->rgb, src->depth);
-		src->src->swap();
+			src->src->swap();
+			src->src->getFrames(src->rgb, src->depth);
 
-		//if (!src->rgb.empty() && src->prev_depth.empty()) {
-			//src->prev_depth = cv::Mat(src->rgb.size(), CV_16UC1, cv::Scalar(0));
-			//LOG(INFO) << "Creating prevdepth: " << src->rgb.cols << "," << src->rgb.rows;
-		//}
-		src->jobs = 0;
-		src->frame++;
+			//if (!src->rgb.empty() && src->prev_depth.empty()) {
+				//src->prev_depth = cv::Mat(src->rgb.size(), CV_16UC1, cv::Scalar(0));
+				//LOG(INFO) << "Creating prevdepth: " << src->rgb.cols << "," << src->rgb.rows;
+			//}
+			src->jobs = -1;
+			src->frame++;
+		}
 	}
 }
 
@@ -310,19 +311,13 @@ void Streamer::wait() {
 }
 
 void Streamer::_schedule(StreamSource *src) {
-	// There will be two jobs for this source...
-	//UNIQUE_LOCK(job_mtx_,lk);
-	jobs_ += 2 + kChunkCount;
-	//lk.unlock();
+	if (src == nullptr || src->jobs > 0) return;
 
-	//StreamSource *src = sources_[uri];
-	if (src == nullptr || src->jobs != 0) return;
+	jobs_ += 2 + kChunkCount;
 	src->jobs = 2 + kChunkCount;
 
 	// Grab / capture job
 	ftl::pool.push([this,src](int id) {
-		//auto start = std::chrono::high_resolution_clock::now();
-
 		auto start = std::chrono::high_resolution_clock::now();
 		int64_t now = std::chrono::time_point_cast<std::chrono::milliseconds>(start).time_since_epoch().count()+clock_adjust_;
 		int64_t target = now / mspf_;
@@ -374,7 +369,7 @@ void Streamer::_schedule(StreamSource *src) {
 		// Mark job as finished
 		std::unique_lock<std::mutex> lk(job_mtx_);
 		--jobs_;
-		job_cv_.notify_one();
+		if (jobs_ == 0) job_cv_.notify_one();
 	});
 
 	// Compute job
@@ -395,7 +390,7 @@ void Streamer::_schedule(StreamSource *src) {
 		// Mark job as finished
 		std::unique_lock<std::mutex> lk(job_mtx_);
 		--jobs_;
-		job_cv_.notify_one();
+		if (jobs_ == 0) job_cv_.notify_one();
 	});
 
 	// Create jobs for each chunk
@@ -415,7 +410,7 @@ void Streamer::_schedule(StreamSource *src) {
 			_swap(src);
 			std::unique_lock<std::mutex> lk(job_mtx_);
 			--jobs_;
-			job_cv_.notify_one();
+			if (jobs_ == 0) job_cv_.notify_one();
 		});
 	}
 }
diff --git a/config/config_nick.jsonc b/config/config_nick.jsonc
index 5e3a29a40abd6da9c577f185584f937c94cf44d0..2dac067a2115b634ec53fa73d58ef702f8d4f1ca 100644
--- a/config/config_nick.jsonc
+++ b/config/config_nick.jsonc
@@ -150,13 +150,13 @@
 			"confidenceThreshold": 0.0,
 			"mls": true,
 			"voxels": false,
-			"clipping": false,
-			"bbox_x_max": 1.5,
-			"bbox_x_min": -1.5,
+			"clipping": true,
+			"bbox_x_max": 0.6,
+			"bbox_x_min": -0.6,
 			"bbox_y_max": 3.0,
 			"bbox_y_min": -3.0,
-			"bbox_z_max": 2.5,
-			"bbox_z_min": 0.0,
+			"bbox_z_max": 3.5,
+			"bbox_z_min": 2.0,
 			"cudaDevice": 1
 		},
 		"rs": {
@@ -507,6 +507,34 @@
 		"stream": {}
 	},
 
+	"reconstruction_snap10": {
+		"net": {
+			"peers": [],
+			"listen": "tcp://*:9002"
+		},
+		"sources": [
+			{"uri":"file:///home/nick/Pictures/FTL/snaptest10.tar.gz#0", "index": "camera0"},
+			{"uri":"file:///home/nick/Pictures/FTL/snaptest10.tar.gz#1", "index": "camera1"},
+			{"uri":"file:///home/nick/Pictures/FTL/snaptest10.tar.gz#2", "index": "camera2"},
+			{"uri":"file:///home/nick/Pictures/FTL/snaptest10.tar.gz#3", "index": "camera3"},
+			{"uri":"file:///home/nick/Pictures/FTL/snaptest10.tar.gz#4", "index": "camera4"}
+		],
+		"display": { "$ref": "#displays/left" },
+		"virtual": { "$ref": "#virtual_cams/default" },
+		"voxelhash": { "$ref": "#hash_conf/default" },
+		"merge": {
+			"$id": "ftl://blah/blah",
+			"targetsource" : "ftl://utu.fi/node3#vision_default/source",
+			"register": false,
+			"chain": false,
+			"maxerror": 100,
+			"iterations" : 10,
+			"delay" : 500,
+			"patternsize" : [9, 6]
+		},
+		"stream": {}
+	},
+
 	"reconstruction_lab": {
 		"net": {
 			"peers": ["tcp://ftl-node-4:9001",