diff --git a/components/renderers/cpp/include/ftl/cuda/normals.hpp b/components/renderers/cpp/include/ftl/cuda/normals.hpp
index 4cfaccc145f0da3d88aca5b4b0c3f015b1b1fbf3..b4d2ced197c383a6d2dc185bf1c8883d6dde356a 100644
--- a/components/renderers/cpp/include/ftl/cuda/normals.hpp
+++ b/components/renderers/cpp/include/ftl/cuda/normals.hpp
@@ -14,7 +14,7 @@ void normals(ftl::cuda::TextureObject<float4> &output,
 
 void normal_visualise(ftl::cuda::TextureObject<float4> &norm,
         ftl::cuda::TextureObject<uchar4> &output,
-        const float3 &light, const float3 &diffuse, const float3 &ambient,
+        const float3 &light, const uchar4 &diffuse, const uchar4 &ambient,
         cudaStream_t stream);
 
 void normal_filter(ftl::cuda::TextureObject<float4> &norm,
diff --git a/components/renderers/cpp/include/ftl/render/splat_render.hpp b/components/renderers/cpp/include/ftl/render/splat_render.hpp
index 5f8a8ba4940e910efd1e9b6f5a0f0e900fde1ff7..af6affb1020ee66b52796bb2cd0e26effa2d11ea 100644
--- a/components/renderers/cpp/include/ftl/render/splat_render.hpp
+++ b/components/renderers/cpp/include/ftl/render/splat_render.hpp
@@ -47,6 +47,9 @@ class Splatter : public ftl::render::Renderer {
 	bool backcull_;
 	cv::Scalar background_;
 	bool splat_;
+	float3 light_dir_;
+	uchar4 light_diffuse_;
+	uchar4 light_ambient_;
 };
 
 }
diff --git a/components/renderers/cpp/src/normals.cu b/components/renderers/cpp/src/normals.cu
index 08fd9794b8c9172eab403cbfc624dedc2c69554a..cbbd0e96797ee11fffd43de0df399a03efcf8db8 100644
--- a/components/renderers/cpp/src/normals.cu
+++ b/components/renderers/cpp/src/normals.cu
@@ -90,7 +90,7 @@ void ftl::cuda::normals(ftl::cuda::TextureObject<float4> &output,
 
 __global__ void vis_normals_kernel(ftl::cuda::TextureObject<float4> norm,
         ftl::cuda::TextureObject<uchar4> output,
-        float3 direction, float3 diffuse, float3 ambient) {
+        float3 direction, uchar4 diffuse, uchar4 ambient) {
     const unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
     const unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;
 
@@ -113,7 +113,7 @@ __global__ void vis_normals_kernel(ftl::cuda::TextureObject<float4> norm,
 
 void ftl::cuda::normal_visualise(ftl::cuda::TextureObject<float4> &norm,
         ftl::cuda::TextureObject<uchar4> &output,
-        const float3 &light, const float3 &diffuse, const float3 &ambient,
+        const float3 &light, const uchar4 &diffuse, const uchar4 &ambient,
         cudaStream_t stream) {
 
     const dim3 gridSize((norm.width() + T_PER_BLOCK - 1)/T_PER_BLOCK, (norm.height() + T_PER_BLOCK - 1)/T_PER_BLOCK);
diff --git a/components/renderers/cpp/src/splat_render.cpp b/components/renderers/cpp/src/splat_render.cpp
index 41d1a4217a1ef3f7f95dab7c23265cd308cdbcfa..d993e145856840e7af545de7365e1e77af7f0866 100644
--- a/components/renderers/cpp/src/splat_render.cpp
+++ b/components/renderers/cpp/src/splat_render.cpp
@@ -25,7 +25,10 @@ static Eigen::Affine3d create_rotation_matrix(float ax, float ay, float az) {
   return rz * rx * ry;
 }
 
-static cv::Scalar parseColour(const std::string &colour) {
+/*
+ * Parse a CSS style colour string into a scalar.
+ */
+static cv::Scalar parseCVColour(const std::string &colour) {
 	std::string c = colour;
 	if (c[0] == '#') {
 		c.erase(0, 1);
@@ -41,6 +44,25 @@ static cv::Scalar parseColour(const std::string &colour) {
 	return cv::Scalar(0,0,0,0);
 }
 
+/*
+ * Parse a CSS style colour string into a scalar.
+ */
+static uchar4 parseCUDAColour(const std::string &colour) {
+	std::string c = colour;
+	if (c[0] == '#') {
+		c.erase(0, 1);
+		unsigned long value = stoul(c.c_str(), nullptr, 16);
+		return make_uchar4(
+			(value >> 0) & 0xff,
+			(value >> 8) & 0xff,
+			(value >> 16) & 0xff,
+			(value >> 24) & 0xff
+		);
+	}
+
+	return make_uchar4(0,0,0,0);
+}
+
 Splatter::Splatter(nlohmann::json &config, ftl::rgbd::FrameSet *fs) : ftl::render::Renderer(config), scene_(fs) {
 	if (config["clipping"].is_object()) {
 		auto &c = config["clipping"];
@@ -84,9 +106,19 @@ Splatter::Splatter(nlohmann::json &config, ftl::rgbd::FrameSet *fs) : ftl::rende
 		splat_ = value("splatting", true);
 	});
 
-	background_ = parseColour(value("background", std::string("#e0e0e0")));
+	background_ = parseCVColour(value("background", std::string("#4c4c4c")));
 	on("background", [this](const ftl::config::Event &e) {
-		background_ = parseColour(value("background", std::string("#e0e0e0")));
+		background_ = parseCVColour(value("background", std::string("#4c4c4c")));
+	});
+
+	light_diffuse_ = parseCUDAColour(value("diffuse", std::string("#e0e0e0")));
+	on("diffuse", [this](const ftl::config::Event &e) {
+		light_diffuse_ = parseCUDAColour(value("diffuse", std::string("#e0e0e0")));
+	});
+
+	light_ambient_ = parseCUDAColour(value("ambient", std::string("#0e0e0e")));
+	on("ambient", [this](const ftl::config::Event &e) {
+		light_ambient_ = parseCUDAColour(value("ambient", std::string("#0e0e0e")));
 	});
 }
 
@@ -324,9 +356,9 @@ bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, cuda
 		// Convert normal to single float value
 		temp_.create<GpuMat>(Channel::Colour, Format<uchar4>(camera.width, camera.height));
 		ftl::cuda::normal_visualise(out.getTexture<float4>(Channel::Normals), temp_.createTexture<uchar4>(Channel::Colour),
-				make_float3(0.0f, 0.0f, 1.0f),
-				make_float3(220,220,220),
-				make_float3(30,30,30), stream);
+				make_float3(-0.3f, 0.2f, 1.0f),
+				light_diffuse_,
+				light_ambient_, stream);
 
 		// Put in output as single float
 		cv::cuda::swap(temp_.get<GpuMat>(Channel::Colour), out.create<GpuMat>(Channel::Normals));