diff --git a/assets/webconfig/c/index.html b/assets/webconfig/c/index.html
new file mode 100644
index 00000000..adbb3e29
--- /dev/null
+++ b/assets/webconfig/c/index.html
@@ -0,0 +1,64 @@
+
+
+
+  
+  Get User Media Code Along!
+  
+  
+
+
+
+  
+
+    
+      
+      
+
+      
+        
+      
+
+      
+
+      
+    
+
+
+
+
+    
+    
+    Color Accuracy: 0%
+    ...
+    
+    
+
+  
+
+  
+  
+  
+  
+  
+
+
+
\ No newline at end of file
diff --git a/assets/webconfig/c/script.js b/assets/webconfig/c/script.js
new file mode 100644
index 00000000..90f73b69
--- /dev/null
+++ b/assets/webconfig/c/script.js
@@ -0,0 +1,752 @@
+var VIDEO_WIDTH = 640,
+		VIDEO_HEIGHT = 480,
+		PORTRAIT,
+		FIX = 2,
+		CURRENT_ADJUSTMENT;
+
+var FAST_COLOR = new FastAverageColor();
+
+
+var is_mobile = mobile_check();
+
+var TV_COLOR_LED = document.querySelector('#tv_color_led');
+var WALL_COLOR_LED = document.querySelector('#wall_color_led');
+var COLOR_TEXT = document.querySelector('#color_text');
+
+var APPLY_BUTTON = document.querySelector('#calibrate_apply');
+
+var video = document.querySelector('#source');
+var CANVAS = document.querySelector('#canvas');
+var ctx = CANVAS.getContext('2d');
+
+var TV_PICKER = document.querySelector('#tv');
+var WALL_PICKER = document.querySelector('#wall');
+
+var TV_COLOR, WALL_COLOR, CURRENT_RGB = [255,255,255], NEW_RGB = [255,255,255], CALIBRATION_MODE, CALIBRATION_MODE_AUTO = 'white',
+		/*
+		COLOR_PICKERS = {
+			'white': document.querySelector('#tv_white'), 'black': document.querySelector('#tv_black'), 'red': document.querySelector('#tv_red'), 'green': document.querySelector('#tv_green'), 'blue': document.querySelector('#tv_blue'), 'cyan': document.querySelector('#tv_cyan'), 'magenta': document.querySelector('#tv_magenta'), 'yellow': document.querySelector('#tv_yellow'), 'wall': WALL_PICKER
+		},
+		COLOR_LEDS = {
+			'white': document.querySelector('#led_white'), 'black': document.querySelector('#led_black'), 'red': document.querySelector('#led_red'), 'green': document.querySelector('#led_green'), 'blue': document.querySelector('#led_blue'), 'cyan': document.querySelector('#led_cyan'), 'magenta': document.querySelector('#led_magenta'), 'yellow': document.querySelector('#led_yellow'), 'wall': document.querySelector('#led_wall')
+		},
+		*/
+		 TV_COLORS = {};
+
+function hyperion_api(data, callback) {
+	$.ajax('/json-rpc', {
+			data : JSON.stringify(data || {command:'serverinfo'}),
+			//data : data || {command:'serverinfo'},
+			//contentType : 'application/json',
+			type : 'POST',
+			success: function(json) {
+				console.log(json);
+				if (callback) callback(json);
+			}
+	});
+}
+
+function update_hyperion_adjustments() {
+	hyperion_api(null, function(json){
+		CURRENT_ADJUSTMENT = json.info.adjustment[0];
+		CURRENT_RGB = CURRENT_ADJUSTMENT[CALIBRATION_MODE_AUTO];
+		console.log(json.info.adjustment[0]);
+	});
+}
+
+var NEW_ADJUSTMENTS = {
+	gammaRed: 1,
+	gammaGreen: 1,
+	gammaBlue: 1,
+	white: [255,255,255], // rgb(253,206,103)
+	red: [255,32,32], // rgb(255,23,3)
+	green: [32,255,32], // rgb(47,255,0)
+	blue: [32,32,255], // rgb(32,14,230)
+	cyan: [128,255,255], // rgb(4,255,90)
+	magenta: [255,1,255], // rgb(82,3,255)
+	yellow: [255,255,1], // rgb(255,206,1)
+};
+
+$(function(){
+
+	update_hyperion_adjustments();
+
+
+	$('#calibrate_init').on('click', function(){
+
+		CALIBRATION_MODE = null;
+
+		hyperion_api({
+			command: "adjustment",
+			adjustment: {
+
+				gammaRed: 1,
+				gammaGreen: 1,
+				gammaBlue: 1,
+				white: [255,255,255], // rgb(253,206,103)
+				red: [255,32,32], // rgb(255,23,3)
+				green: [32,255,32], // rgb(47,255,0)
+				blue: [32,32,255], // rgb(32,14,230)
+				cyan: [128,255,255], // rgb(4,255,90)
+				magenta: [255,1,255], // rgb(82,3,255)
+				yellow: [255,255,1], // rgb(255,206,1)
+
+			},
+		});
+
+		$(this).addClass('auto');
+
+		return false;
+	});
+
+	$('#calibrate_white').on('click', function(){
+
+		CALIBRATION_MODE = 'white';
+
+		hyperion_api({
+			command: 'color',
+			color: CURRENT_ADJUSTMENT.white,
+			priority: 50,
+			origin: 'Calibrator',
+		}, function(){
+		});
+
+		return false;
+	});
+
+
+	$('#calibrate_red').on('click', function(){
+
+		CALIBRATION_MODE = 'red';
+
+		hyperion_api({
+			command: 'color',
+			color: CURRENT_ADJUSTMENT.red,
+			priority: 50,
+			origin: 'Calibrator',
+		}, function(){
+		});
+
+		return false;
+	});
+
+	$('#calibrate_green').on('click', function(){
+
+		CALIBRATION_MODE = 'green';
+
+		hyperion_api({
+			command: 'color',
+			color: CURRENT_ADJUSTMENT.green,
+			priority: 50,
+			origin: 'Calibrator',
+		}, function(){
+		});
+
+		return false;
+	});
+
+	$('#calibrate_blue').on('click', function(){
+
+		CALIBRATION_MODE = 'blue';
+
+		hyperion_api({
+			command: 'color',
+			color: CURRENT_ADJUSTMENT.blue,
+			priority: 50,
+			origin: 'Calibrator',
+		}, function(){
+		});
+
+		return false;
+	});
+
+	$('#calibrate_cyan').on('click', function(){
+
+		CALIBRATION_MODE = 'cyan';
+
+		hyperion_api({
+			command: 'color',
+			color: CURRENT_ADJUSTMENT.cyan,
+			priority: 50,
+			origin: 'Calibrator',
+		}, function(){
+		});
+
+		return false;
+	});
+
+	$('#calibrate_magenta').on('click', function(){
+
+		CALIBRATION_MODE = 'magenta';
+
+		hyperion_api({
+			command: 'color',
+			color: CURRENT_ADJUSTMENT.magenta,
+			priority: 50,
+			origin: 'Calibrator',
+		}, function(){
+		});
+
+		return false;
+	});
+
+	$('#calibrate_yellow').on('click', function(){
+
+		CALIBRATION_MODE = 'yellow';
+
+		hyperion_api({
+			command: 'color',
+			color: CURRENT_ADJUSTMENT.yellow,
+			priority: 50,
+			origin: 'Calibrator',
+		}, function(){
+		});
+
+		return false;
+	});
+
+	$('#calibrate_off').on('click', function(){
+
+		CALIBRATION_MODE = null;
+
+		hyperion_api({
+			command: 'clear',
+			priority: 50,
+		}, function(){
+
+		});
+
+		return false;
+	});
+
+	$('#calibrate_apply').on('click', function(){
+
+		hyperion_api({
+			command: "adjustment",
+			adjustment: {
+				[CALIBRATION_MODE_AUTO]: NEW_RGB, // rgb(255,220,90)
+			},
+		}, function() {
+
+			update_hyperion_adjustments();
+
+		});
+
+		return false;
+	});
+
+});
+
+
+//var snap = document.querySelector('.snap');
+
+let portrait = window.matchMedia("(orientation: portrait)");
+
+PORTRAIT = portrait.matches;
+
+portrait.addEventListener("change", function(e) {
+		if(e.matches) {
+				// Portrait mode
+				PORTRAIT = true;
+		} else {
+				// Landscape
+				PORTRAIT = false;
+		}
+
+		get_video();
+		//update_canvas();
+})
+
+function mobile_check() {
+	let check = false;
+	(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
+	return check;
+};
+
+// Fix for iOS Safari from https://leemartin.dev/hello-webrtc-on-safari-11-e8bcb5335295
+//video.setAttribute('autoplay', '');
+//video.setAttribute('muted', '');
+//video.setAttribute('playsinline', '')
+
+function get_video() {
+
+	var varraints = {
+		audio: false,
+		video: {
+			facingMode: 'environment',
+			//noiseSuppression: true,
+			frameRate: 30,
+			//width: 640,
+			//height: 480,
+			aspectRatio: is_mobile ? (PORTRAIT ? 3/4 : 4/3) : 4/3,
+	/*
+			advanced: [
+				{
+					exposureMode: 'manual',
+					exposureTime: 4,
+				}
+			],
+	*/
+		}
+	}
+
+	//varraints = {audio: false, video: true};
+
+	//alert(varraints.video.aspectRatio);
+
+	navigator.mediaDevices.getUserMedia(varraints)
+		.then(localMediaStream => {
+
+			//video.pause();
+
+			//var track = localMediaStream.getVideoTracks()[0];
+
+
+			//console.log('The device supports the following capabilities: ', track.getCapabilities());
+/*
+						 // set manual exposure mode
+						 track.applyvarraints({
+								 advanced: [
+										 {exposureMode: 'manual'}
+								 ]})
+								 .then(() => {
+										 // set target value for exposure time
+										 track.applyvarraints({
+												 advanced: [
+														 {exposureTime: 8}
+												 ]})
+												 .then(() => {
+														 // success
+														 console.log('The new device settings are: ', track.getSettings());
+												 })
+												 .catch(e => {
+														 console.error('Failed to set exposure time', e);
+												 });
+								 })
+								 .catch(e => {
+										 console.error('Failed to set manual exposure mode', e);
+								 });
+ */
+
+//  DEPRECIATION : 
+//       The following has been depreceated by major browsers as of Chrome and Firefox.
+//       video.src = window.URL.createObjectURL(localMediaStream);
+//       Please refer to these:
+//       Deprecated  - https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
+//       Newer Syntax - https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/srcObject
+			//console.dir(video);
+
+
+			if ('srcObject' in video) {
+				video.srcObject = localMediaStream;
+			} else {
+				video.src = URL.createObjectURL(localMediaStream);
+			}
+			// video.src = window.URL.createObjectURL(localMediaStream);
+
+			video.play();
+		})
+		.catch(err => {
+			console.error(`OH NO!!!!`, err);
+		});
+}
+
+function update_canvas() {
+	CANVAS.width = VIDEO_WIDTH;
+	CANVAS.height = VIDEO_HEIGHT;
+}
+
+function refresh_canvas() {
+	ctx.drawImage(video, 0, 0, VIDEO_WIDTH, VIDEO_HEIGHT);
+	
+
+	// take the pixels out
+	
+	//var pixels = ctx.getImageData(0, 0, VIDEO_WIDTH, VIDEO_HEIGHT);
+	// mess with them
+	// pixels = redEffect(pixels);
+
+	//pixels = rgbSplit(pixels);
+	//ctx.globalAlpha = 0.8;
+
+	// pixels = greenScreen(pixels);
+	
+	// put them back
+	//ctx.putImageData(pixels, 0, 0);
+
+	requestAnimationFrame(function() {
+		requestAnimationFrame(refresh_canvas);
+	});
+}
+
+
+
+
+function takePhoto() {
+	// played the sound
+	
+	//snap.currentTime = 0;
+	//snap.play();
+
+	// take the data out of the canvas
+	var data = CANVAS.toDataURL('image/jpeg');
+	var link = document.createElement('a');
+	link.href = data;
+	link.setAttribute('download', 'handsome');
+	link.innerHTML = ` `;
+	strip.insertBefore(link, strip.firstChild);
+}
+
+function redEffect(pixels) {
+	for (let i = 0; i < pixels.data.length; i+=4) {
+		pixels.data[i + 0] = pixels.data[i + 0] + 200; // RED
+		pixels.data[i + 1] = pixels.data[i + 1] - 50; // GREEN
+		pixels.data[i + 2] = pixels.data[i + 2] * 0.5; // Blue
+	}
+	return pixels;
+}
+
+function rgbSplit(pixels) {
+	for (let i = 0; i < pixels.data.length; i+=4) {
+		pixels.data[i - 150] = pixels.data[i + 0]; // RED
+		pixels.data[i + 500] = pixels.data[i + 1]; // GREEN
+		pixels.data[i - 550] = pixels.data[i + 2]; // Blue
+	}
+	return pixels;
+}
+
+video.addEventListener('canplay', function(){
+
+	update_canvas();
+	refresh_canvas();
+
+	update_colors();
+
+});
+
+get_video();
+
+function update_colors() {
+
+	/*
+
+	COLOR_TEXT.innerText = Object.keys(TV_COLORS).map(function(key){return key+":\t"+TV_COLORS[key]}).join("\n");
+
+	var tmp_color_pickers = JSON.parse(JSON.stringify(Object.keys(COLOR_PICKERS)));
+
+	function get_picker_color() {
+		var color_picker_id = tmp_color_pickers.pop(),
+				picker_element = COLOR_PICKERS[color_picker_id];
+
+		FAST_COLOR.getColorAsync(CANVAS, {
+
+			algorithm: 'simple', // simple, sqrt, dominant
+			mode: 'speed', // speed, precision
+			//step: 1,
+
+			left: picker_element.offsetLeft - picker_element.clientWidth/2,
+			top: picker_element.offsetTop - picker_element.clientHeight/2,
+			width: picker_element.clientWidth,
+			height: picker_element.clientHeight,
+
+		}).then(color => {
+
+				COLOR_LEDS[color_picker_id].style.backgroundColor = color.hex;
+				TV_COLORS[color_picker_id] = color.value.slice(0,3);
+
+
+				if (tmp_color_pickers.length) {
+					get_picker_color();
+				} else {
+					requestAnimationFrame(update_colors);
+				}
+		});
+	}
+
+	get_picker_color();
+
+	return false;
+*/
+
+	CURRENT_RGB = CURRENT_ADJUSTMENT[CALIBRATION_MODE_AUTO] || [255,255,255];
+
+	FAST_COLOR.getColorAsync(CANVAS, {
+		algorithm: 'simple', // simple, sqrt, dominant
+		mode: 'speed', // speed, precision
+		//step: 1,
+
+		left: TV_PICKER.offsetLeft - TV_PICKER.clientWidth/2,
+		top: TV_PICKER.offsetTop - TV_PICKER.clientHeight/2,
+		width: TV_PICKER.clientWidth,
+		height: TV_PICKER.clientHeight,
+
+		ignoredColor: [0,0,0,255],
+
+	}).then(color => {
+		//console.log(color);
+		delete(color.rgba);
+		delete(color.hexa);
+
+		TV_COLOR = color;
+		TV_COLOR_LED.style.backgroundColor = color.hex;
+
+		FAST_COLOR.getColorAsync(CANVAS, {
+			algorithm: 'simple', // simple, sqrt, dominant
+			mode: 'speed', // speed, precision
+			//step: 1,
+
+			left: WALL_PICKER.offsetLeft - WALL_PICKER.clientWidth/2,
+			top: WALL_PICKER.offsetTop - WALL_PICKER.clientHeight/2,
+			width: WALL_PICKER.clientWidth,
+			height: WALL_PICKER.clientHeight,
+
+			ignoredColor: [0,0,0,255],
+
+
+		}).then(color => {
+			//console.log(color);
+			delete(color.rgba);
+			delete(color.hexa);
+
+			WALL_COLOR = color;
+			WALL_COLOR_LED.style.backgroundColor = color.hex;
+
+			var hsl_tv = rgb_to_hsl(TV_COLOR.value[0], TV_COLOR.value[1], TV_COLOR.value[2]);
+			var hsl_wall = rgb_to_hsl(WALL_COLOR.value[0], WALL_COLOR.value[1], WALL_COLOR.value[2]);
+
+			//COLOR_TEXT.innerText = ~~Math.abs(hsl_tv[0] - hsl_wall[0]);
+
+			var tv_rgb = TV_COLOR.value.slice(0,3).map(function(n){return Math.max(n,1)}),
+					wall_rgb = WALL_COLOR.value.slice(0,3).map(function(n){return Math.max(n,1)}),
+					tv_rgb_min = Math.max(1, Math.min(...tv_rgb)),
+					wall_rgb_min = Math.max(1, Math.min(...wall_rgb)),
+					tv_rgb_max = Math.max(1, Math.max(...tv_rgb)),
+					wall_rgb_max = Math.max(...wall_rgb),
+					tv_adjusted_rgb = [(tv_rgb[0]/tv_rgb_min).toFixed(FIX), (tv_rgb[1]/tv_rgb_min).toFixed(FIX), (tv_rgb[2]/tv_rgb_min).toFixed(FIX)],
+					wall_adjusted_rgb = [(wall_rgb[0]/wall_rgb_min).toFixed(FIX), (wall_rgb[1]/wall_rgb_min).toFixed(FIX), (wall_rgb[2]/wall_rgb_min).toFixed(FIX)];
+
+			CALIBRATION_MODE_AUTO = null;
+
+
+				if (tv_rgb_min > 130) CALIBRATION_MODE_AUTO = 'white';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[0]/tv_adjusted_rgb[1] > 2 && tv_adjusted_rgb[0]/tv_adjusted_rgb[2] > 2) CALIBRATION_MODE_AUTO = 'red';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[1]/tv_adjusted_rgb[0] > 2 && tv_adjusted_rgb[1]/tv_adjusted_rgb[2] > 2) CALIBRATION_MODE_AUTO = 'green';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[2]/tv_adjusted_rgb[0] > 2 && tv_adjusted_rgb[2]/tv_adjusted_rgb[1] > 2) CALIBRATION_MODE_AUTO = 'blue';
+
+				if (!CALIBRATION_MODE_AUTO && Math.abs(tv_adjusted_rgb[1]-tv_adjusted_rgb[2]) < 1 && tv_adjusted_rgb[1]/tv_adjusted_rgb[0] > 1.5 && tv_adjusted_rgb[2]/tv_adjusted_rgb[0] > 1.5) CALIBRATION_MODE_AUTO = 'cyan';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[0]/tv_adjusted_rgb[1] > 2 && tv_adjusted_rgb[2]/tv_adjusted_rgb[1] > 2) CALIBRATION_MODE_AUTO = 'magenta';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[0]/tv_adjusted_rgb[2] > 1.5 && tv_adjusted_rgb[1]/tv_adjusted_rgb[2] > 1.5) CALIBRATION_MODE_AUTO = 'yellow';
+
+				if (CALIBRATION_MODE) CALIBRATION_MODE_AUTO = CALIBRATION_MODE;
+
+				$('#controls button').removeClass('auto');
+				$('#calibrate_'+CALIBRATION_MODE_AUTO).addClass('auto');
+
+
+			var accuracy_multiplier = [];
+
+
+			if (CALIBRATION_MODE_AUTO == 'white') {
+				NEW_RGB[0] = Math.round(255 * wall_rgb_min/wall_rgb[0]);
+				NEW_RGB[1] = Math.round(255 * wall_rgb_min/wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * wall_rgb_min/wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'red') {
+
+				//NEW_RGB[0] = Math.round(CURRENT_RGB[0]);
+				NEW_RGB[0] = Math.round(255 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(CURRENT_RGB[1] * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(CURRENT_RGB[2] * tv_rgb[2] / wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'green') {
+
+				NEW_RGB[0] = Math.round(CURRENT_RGB[0] * tv_rgb[0] / wall_rgb[0]);
+				//NEW_RGB[1] = Math.round(CURRENT_RGB[1]);
+				NEW_RGB[1] = Math.round(255 * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(CURRENT_RGB[2] * tv_rgb[2] / wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'blue') {
+				NEW_RGB[0] = Math.round(CURRENT_RGB[0] * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(CURRENT_RGB[1] * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * tv_rgb[2] / wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'cyan') {
+
+				NEW_RGB[0] = Math.round(128 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(255 * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * tv_rgb[2] / wall_rgb[2]);
+
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'magenta') {
+
+				NEW_RGB[0] = Math.round(255 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(Math.max(1, CURRENT_RGB[1]) * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * tv_rgb[2] / wall_rgb[2]);
+
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'yellow') {
+
+				NEW_RGB[0] = Math.round(255 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(255 * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(CURRENT_RGB[2] * tv_rgb[2] / wall_rgb[2]);
+
+			}
+
+			// calculate current color accuracy
+
+			if (CALIBRATION_MODE_AUTO) {
+				var color1 = new Color('rgb(' + tv_rgb.join(',') + ')');
+				var color2 = new Color('rgb(' + wall_rgb.join(',') + ')');
+				var colorDistance = color1.deltaE76(color2);
+				WALL_COLOR_LED.innerText = CALIBRATION_MODE_AUTO + ' accuracy: ' + Math.round(100 - colorDistance) + '%';
+
+				APPLY_BUTTON.innerText = 'APPLY ' + CALIBRATION_MODE_AUTO + ' CALIBRATION';
+			} else {
+				APPLY_BUTTON.innerText = 'APPLY CALIBRATION';
+			}
+
+			// normalize new rgb
+
+			var new_rgb_max = Math.max(...NEW_RGB),
+				new_rgb_min = Math.min(...NEW_RGB);
+
+			if (new_rgb_max > 255) {
+				NEW_RGB = NEW_RGB.map(function(n){
+					return Math.round(n * 255 / new_rgb_max);
+				});
+			}
+
+			COLOR_TEXT.innerText = [
+				'CURRENT COLOR: ' + CURRENT_RGB.join(':'),
+				'MODE: ' + CALIBRATION_MODE_AUTO,
+				'TV: ' + tv_rgb.join(':'),
+				'WALL: ' + wall_rgb.join(':'),
+				'TV ADJUSTED: ' + tv_adjusted_rgb.join(':'),
+				'WALL ADJUSTED: ' + wall_adjusted_rgb.join(':'),
+
+				NEW_RGB.join(':'),
+			].join("\n");
+
+			requestAnimationFrame(function(){
+				//requestAnimationFrame(update_colors);
+				setTimeout(update_colors, 1111);
+			});
+
+		});
+	});
+
+}
+
+// COLOR MAGIC
+
+function rgb_to_hsl(r,g,b) {
+	r = r / 255;
+	g = g / 255;
+	b = b / 255;
+
+	var max = Math.max(r, g, b),
+			min = Math.min(r, g, b),
+			h, s, l = (max + min) / 2;
+
+	if (max == min) {
+		h = s = 0; // achromatic
+	} else {
+		var d = max - min;
+		s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+
+		switch (max) {
+			case r:
+				h = (g - b) / d + (g < b ? 6 : 0);
+				break;
+			case g:
+				h = (b - r) / d + 2;
+				break;
+			case b:
+				h = (r - g) / d + 4;
+				break;
+		}
+
+		h /= 6;
+	}
+
+	h *= 360;
+	s *= 100;
+	l *= 100;
+
+	return [h, s, l];
+}
+
+function hsl_to_rgb(h,s,l) {
+	var h = h / 360;
+	var s = s / 100;
+	var l = l / 100;
+
+	var r, g, b;
+
+	if (s == 0) {
+		r = g = b = l; // achromatic
+	} else {
+		function hue_to_rgb(p, q, t) {
+			if (t < 0) t += 1;
+			if (t > 1) t -= 1;
+			if (t < 1/6) return p + (q - p) * 6 * t;
+			if (t < 1/2) return q;
+			if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
+			return p;
+		}
+
+		var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+		var p = 2 * l - q;
+
+		r = hue_to_rgb(p, q, h + 1/3);
+		g = hue_to_rgb(p, q, h);
+		b = hue_to_rgb(p, q, h - 1/3);
+	}
+
+	r *= 255;
+	g *= 255;
+	b *= 255;
+
+	return [r, g, b];
+}
+
+function delta_e(rgb_a, rgb_b) {
+	var labA = rgb_to_lab(rgb_a[0], rgb_a[1], rgb_a[2]);
+	var labB = rgb_to_lab(rgb_b[0], rgb_b[1], rgb_b[2]);
+	var deltaL = labA[0] - labB[0];
+	var deltaA = labA[1] - labB[1];
+	var deltaB = labA[2] - labB[2];
+	var c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
+	var c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
+	var deltaC = c1 - c2;
+	var deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
+	deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
+	var sc = 1.0 + 0.045 * c1;
+	var sh = 1.0 + 0.015 * c1;
+	var deltaLKlsl = deltaL / (1.0);
+	var deltaCkcsc = deltaC / (sc);
+	var deltaHkhsh = deltaH / (sh);
+	var i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
+	return i < 0 ? 0 : Math.sqrt(i);
+}
+
+function rgb_to_lab(r,g,b){
+	var r = r / 255, g = g / 255, b = b / 255, x, y, z;
+	r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
+	g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
+	b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
+	x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
+	y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
+	z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
+	x = (x > 0.008856) ? Math.pow(x, 1/3) : (7.787 * x) + 16/116;
+	y = (y > 0.008856) ? Math.pow(y, 1/3) : (7.787 * y) + 16/116;
+	z = (z > 0.008856) ? Math.pow(z, 1/3) : (7.787 * z) + 16/116;
+	return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)];
+}
+
diff --git a/assets/webconfig/c/styles.css b/assets/webconfig/c/styles.css
new file mode 100644
index 00000000..f9398cd1
--- /dev/null
+++ b/assets/webconfig/c/styles.css
@@ -0,0 +1,201 @@
+* {
+	border: 0;
+	margin: 0;
+	padding: 0;
+	overflow: hidden;
+	outline: none;
+	background: none;
+	font-size: 0;
+	line-height: 0;
+}
+
+html, body {
+	background: #111;
+	color: fff;
+}
+
+#camera {
+	position: relative;
+}
+
+#wall,
+#tv {
+	position: absolute;
+	top: 50%;
+	width: 32px;
+	height: 332px;
+	border-radius: 8px;
+	border: 4px solid #fff;
+
+	transform: translate(-50%, -50%);
+
+	opacity: .5;
+}
+
+#tv {
+	left: 30%;
+	width: 136px;
+}
+
+#wall {
+	left: 70%;
+	width: 136px;
+	border-style: dotted;
+}
+
+#tv ins {
+	left: 40%;
+	height: 32px;
+}
+#tv ins#tv_white,
+#tv ins#tv_black {
+	left: calc(40% - 60px);
+	height: 332px;
+}
+#tv ins#tv_red {
+	top: 90px;
+}
+#tv ins#tv_green {
+	top: 150px;
+}
+#tv ins#tv_blue {
+	top: 210px;
+}
+#tv ins#tv_cyan {
+	top: 270px;
+}
+#tv ins#tv_magenta {
+	top: 330px;
+}
+#tv ins#tv_yellow {
+	top: 390px;
+}
+#tv ins#tv_black {
+	left: calc(40% - 120px);
+}
+
+.lock {
+	opacity: 1;
+}
+
+#calibration {
+	max-width: 640px;
+	margin: 0 auto;
+	position: relative;
+}
+#canvas {
+	display: block;
+
+	width: 640px;
+	height: 480px;
+	border-radius: 4px;
+	background: #333;
+}
+
+#source {
+	display: none;
+}
+
+#tv_color_led,
+#wall_color_led {
+	display: inline-block;
+	width: 50%;
+	height: 32px;
+	background: #222;
+
+	color: #fff;
+	text-transform: uppercase;
+	text-align: center;
+	font: normal 12px/32px Monospace;
+}
+
+#color_leds {
+	display: block;
+	height: 64px;
+}
+#color_leds ins {
+	width: calc(100% / 8);
+	display: inline-block;
+	height: 32px;
+}
+#color_leds ins#led_wall {
+	width: 100%;
+}
+
+#tv ins#tv_red {
+	border-color: red;
+}
+#tv ins#tv_green {
+	border-color: green;
+}
+#tv ins#tv_blue {
+	border-color: blue;
+}
+#tv ins#tv_cyan {
+	border-color: cyan;
+}
+#tv ins#tv_magenta {
+	border-color: magenta;
+}
+#tv ins#tv_yellow {
+	border-color: yellow;
+}
+#tv ins#tv_black {
+	border-color: black;
+}
+v
+#tv ins#tv_white {
+	border-color: white;
+}
+
+#tv_wall_devider {
+	position: absolute;
+	width: 0;
+	border-radius: 0;
+	border: 2px dashed #fff;
+	height: 100vh;
+	top: 0;
+	bottom: 0;
+	left: 50%;
+	opacity: .5;
+}
+
+#color_text {
+	display: inline-block;
+	font: normal 10px/24px Monospace;
+	color: #fff;
+
+	display: none;
+
+}
+
+button {
+	padding: 0 16px;
+	background: #666;
+	color: #fff;
+	text-transform: uppercase;
+	min-width: 60px;
+
+	font: normal 10px/24px Monospace;
+	margin: 8px 0;
+
+	transition: background .2s;
+}
+button.auto {
+	background: #aaa;
+}
+
+#controls {
+	align-items: baseline;
+	display: flex;
+	justify-content: space-between;
+}
+
+#calibrate_init {
+	margin-left: 0;
+}
+#calibrate_apply {
+	margin: 8px 0;
+	width: 100%;
+	padding: 0;
+}
\ No newline at end of file
`;
+	strip.insertBefore(link, strip.firstChild);
+}
+
+function redEffect(pixels) {
+	for (let i = 0; i < pixels.data.length; i+=4) {
+		pixels.data[i + 0] = pixels.data[i + 0] + 200; // RED
+		pixels.data[i + 1] = pixels.data[i + 1] - 50; // GREEN
+		pixels.data[i + 2] = pixels.data[i + 2] * 0.5; // Blue
+	}
+	return pixels;
+}
+
+function rgbSplit(pixels) {
+	for (let i = 0; i < pixels.data.length; i+=4) {
+		pixels.data[i - 150] = pixels.data[i + 0]; // RED
+		pixels.data[i + 500] = pixels.data[i + 1]; // GREEN
+		pixels.data[i - 550] = pixels.data[i + 2]; // Blue
+	}
+	return pixels;
+}
+
+video.addEventListener('canplay', function(){
+
+	update_canvas();
+	refresh_canvas();
+
+	update_colors();
+
+});
+
+get_video();
+
+function update_colors() {
+
+	/*
+
+	COLOR_TEXT.innerText = Object.keys(TV_COLORS).map(function(key){return key+":\t"+TV_COLORS[key]}).join("\n");
+
+	var tmp_color_pickers = JSON.parse(JSON.stringify(Object.keys(COLOR_PICKERS)));
+
+	function get_picker_color() {
+		var color_picker_id = tmp_color_pickers.pop(),
+				picker_element = COLOR_PICKERS[color_picker_id];
+
+		FAST_COLOR.getColorAsync(CANVAS, {
+
+			algorithm: 'simple', // simple, sqrt, dominant
+			mode: 'speed', // speed, precision
+			//step: 1,
+
+			left: picker_element.offsetLeft - picker_element.clientWidth/2,
+			top: picker_element.offsetTop - picker_element.clientHeight/2,
+			width: picker_element.clientWidth,
+			height: picker_element.clientHeight,
+
+		}).then(color => {
+
+				COLOR_LEDS[color_picker_id].style.backgroundColor = color.hex;
+				TV_COLORS[color_picker_id] = color.value.slice(0,3);
+
+
+				if (tmp_color_pickers.length) {
+					get_picker_color();
+				} else {
+					requestAnimationFrame(update_colors);
+				}
+		});
+	}
+
+	get_picker_color();
+
+	return false;
+*/
+
+	CURRENT_RGB = CURRENT_ADJUSTMENT[CALIBRATION_MODE_AUTO] || [255,255,255];
+
+	FAST_COLOR.getColorAsync(CANVAS, {
+		algorithm: 'simple', // simple, sqrt, dominant
+		mode: 'speed', // speed, precision
+		//step: 1,
+
+		left: TV_PICKER.offsetLeft - TV_PICKER.clientWidth/2,
+		top: TV_PICKER.offsetTop - TV_PICKER.clientHeight/2,
+		width: TV_PICKER.clientWidth,
+		height: TV_PICKER.clientHeight,
+
+		ignoredColor: [0,0,0,255],
+
+	}).then(color => {
+		//console.log(color);
+		delete(color.rgba);
+		delete(color.hexa);
+
+		TV_COLOR = color;
+		TV_COLOR_LED.style.backgroundColor = color.hex;
+
+		FAST_COLOR.getColorAsync(CANVAS, {
+			algorithm: 'simple', // simple, sqrt, dominant
+			mode: 'speed', // speed, precision
+			//step: 1,
+
+			left: WALL_PICKER.offsetLeft - WALL_PICKER.clientWidth/2,
+			top: WALL_PICKER.offsetTop - WALL_PICKER.clientHeight/2,
+			width: WALL_PICKER.clientWidth,
+			height: WALL_PICKER.clientHeight,
+
+			ignoredColor: [0,0,0,255],
+
+
+		}).then(color => {
+			//console.log(color);
+			delete(color.rgba);
+			delete(color.hexa);
+
+			WALL_COLOR = color;
+			WALL_COLOR_LED.style.backgroundColor = color.hex;
+
+			var hsl_tv = rgb_to_hsl(TV_COLOR.value[0], TV_COLOR.value[1], TV_COLOR.value[2]);
+			var hsl_wall = rgb_to_hsl(WALL_COLOR.value[0], WALL_COLOR.value[1], WALL_COLOR.value[2]);
+
+			//COLOR_TEXT.innerText = ~~Math.abs(hsl_tv[0] - hsl_wall[0]);
+
+			var tv_rgb = TV_COLOR.value.slice(0,3).map(function(n){return Math.max(n,1)}),
+					wall_rgb = WALL_COLOR.value.slice(0,3).map(function(n){return Math.max(n,1)}),
+					tv_rgb_min = Math.max(1, Math.min(...tv_rgb)),
+					wall_rgb_min = Math.max(1, Math.min(...wall_rgb)),
+					tv_rgb_max = Math.max(1, Math.max(...tv_rgb)),
+					wall_rgb_max = Math.max(...wall_rgb),
+					tv_adjusted_rgb = [(tv_rgb[0]/tv_rgb_min).toFixed(FIX), (tv_rgb[1]/tv_rgb_min).toFixed(FIX), (tv_rgb[2]/tv_rgb_min).toFixed(FIX)],
+					wall_adjusted_rgb = [(wall_rgb[0]/wall_rgb_min).toFixed(FIX), (wall_rgb[1]/wall_rgb_min).toFixed(FIX), (wall_rgb[2]/wall_rgb_min).toFixed(FIX)];
+
+			CALIBRATION_MODE_AUTO = null;
+
+
+				if (tv_rgb_min > 130) CALIBRATION_MODE_AUTO = 'white';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[0]/tv_adjusted_rgb[1] > 2 && tv_adjusted_rgb[0]/tv_adjusted_rgb[2] > 2) CALIBRATION_MODE_AUTO = 'red';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[1]/tv_adjusted_rgb[0] > 2 && tv_adjusted_rgb[1]/tv_adjusted_rgb[2] > 2) CALIBRATION_MODE_AUTO = 'green';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[2]/tv_adjusted_rgb[0] > 2 && tv_adjusted_rgb[2]/tv_adjusted_rgb[1] > 2) CALIBRATION_MODE_AUTO = 'blue';
+
+				if (!CALIBRATION_MODE_AUTO && Math.abs(tv_adjusted_rgb[1]-tv_adjusted_rgb[2]) < 1 && tv_adjusted_rgb[1]/tv_adjusted_rgb[0] > 1.5 && tv_adjusted_rgb[2]/tv_adjusted_rgb[0] > 1.5) CALIBRATION_MODE_AUTO = 'cyan';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[0]/tv_adjusted_rgb[1] > 2 && tv_adjusted_rgb[2]/tv_adjusted_rgb[1] > 2) CALIBRATION_MODE_AUTO = 'magenta';
+				if (!CALIBRATION_MODE_AUTO && tv_adjusted_rgb[0]/tv_adjusted_rgb[2] > 1.5 && tv_adjusted_rgb[1]/tv_adjusted_rgb[2] > 1.5) CALIBRATION_MODE_AUTO = 'yellow';
+
+				if (CALIBRATION_MODE) CALIBRATION_MODE_AUTO = CALIBRATION_MODE;
+
+				$('#controls button').removeClass('auto');
+				$('#calibrate_'+CALIBRATION_MODE_AUTO).addClass('auto');
+
+
+			var accuracy_multiplier = [];
+
+
+			if (CALIBRATION_MODE_AUTO == 'white') {
+				NEW_RGB[0] = Math.round(255 * wall_rgb_min/wall_rgb[0]);
+				NEW_RGB[1] = Math.round(255 * wall_rgb_min/wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * wall_rgb_min/wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'red') {
+
+				//NEW_RGB[0] = Math.round(CURRENT_RGB[0]);
+				NEW_RGB[0] = Math.round(255 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(CURRENT_RGB[1] * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(CURRENT_RGB[2] * tv_rgb[2] / wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'green') {
+
+				NEW_RGB[0] = Math.round(CURRENT_RGB[0] * tv_rgb[0] / wall_rgb[0]);
+				//NEW_RGB[1] = Math.round(CURRENT_RGB[1]);
+				NEW_RGB[1] = Math.round(255 * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(CURRENT_RGB[2] * tv_rgb[2] / wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'blue') {
+				NEW_RGB[0] = Math.round(CURRENT_RGB[0] * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(CURRENT_RGB[1] * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * tv_rgb[2] / wall_rgb[2]);
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'cyan') {
+
+				NEW_RGB[0] = Math.round(128 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(255 * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * tv_rgb[2] / wall_rgb[2]);
+
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'magenta') {
+
+				NEW_RGB[0] = Math.round(255 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(Math.max(1, CURRENT_RGB[1]) * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(255 * tv_rgb[2] / wall_rgb[2]);
+
+			}
+
+			if (CALIBRATION_MODE_AUTO == 'yellow') {
+
+				NEW_RGB[0] = Math.round(255 * tv_rgb[0] / wall_rgb[0]);
+				NEW_RGB[1] = Math.round(255 * tv_rgb[1] / wall_rgb[1]);
+				NEW_RGB[2] = Math.round(CURRENT_RGB[2] * tv_rgb[2] / wall_rgb[2]);
+
+			}
+
+			// calculate current color accuracy
+
+			if (CALIBRATION_MODE_AUTO) {
+				var color1 = new Color('rgb(' + tv_rgb.join(',') + ')');
+				var color2 = new Color('rgb(' + wall_rgb.join(',') + ')');
+				var colorDistance = color1.deltaE76(color2);
+				WALL_COLOR_LED.innerText = CALIBRATION_MODE_AUTO + ' accuracy: ' + Math.round(100 - colorDistance) + '%';
+
+				APPLY_BUTTON.innerText = 'APPLY ' + CALIBRATION_MODE_AUTO + ' CALIBRATION';
+			} else {
+				APPLY_BUTTON.innerText = 'APPLY CALIBRATION';
+			}
+
+			// normalize new rgb
+
+			var new_rgb_max = Math.max(...NEW_RGB),
+				new_rgb_min = Math.min(...NEW_RGB);
+
+			if (new_rgb_max > 255) {
+				NEW_RGB = NEW_RGB.map(function(n){
+					return Math.round(n * 255 / new_rgb_max);
+				});
+			}
+
+			COLOR_TEXT.innerText = [
+				'CURRENT COLOR: ' + CURRENT_RGB.join(':'),
+				'MODE: ' + CALIBRATION_MODE_AUTO,
+				'TV: ' + tv_rgb.join(':'),
+				'WALL: ' + wall_rgb.join(':'),
+				'TV ADJUSTED: ' + tv_adjusted_rgb.join(':'),
+				'WALL ADJUSTED: ' + wall_adjusted_rgb.join(':'),
+
+				NEW_RGB.join(':'),
+			].join("\n");
+
+			requestAnimationFrame(function(){
+				//requestAnimationFrame(update_colors);
+				setTimeout(update_colors, 1111);
+			});
+
+		});
+	});
+
+}
+
+// COLOR MAGIC
+
+function rgb_to_hsl(r,g,b) {
+	r = r / 255;
+	g = g / 255;
+	b = b / 255;
+
+	var max = Math.max(r, g, b),
+			min = Math.min(r, g, b),
+			h, s, l = (max + min) / 2;
+
+	if (max == min) {
+		h = s = 0; // achromatic
+	} else {
+		var d = max - min;
+		s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+
+		switch (max) {
+			case r:
+				h = (g - b) / d + (g < b ? 6 : 0);
+				break;
+			case g:
+				h = (b - r) / d + 2;
+				break;
+			case b:
+				h = (r - g) / d + 4;
+				break;
+		}
+
+		h /= 6;
+	}
+
+	h *= 360;
+	s *= 100;
+	l *= 100;
+
+	return [h, s, l];
+}
+
+function hsl_to_rgb(h,s,l) {
+	var h = h / 360;
+	var s = s / 100;
+	var l = l / 100;
+
+	var r, g, b;
+
+	if (s == 0) {
+		r = g = b = l; // achromatic
+	} else {
+		function hue_to_rgb(p, q, t) {
+			if (t < 0) t += 1;
+			if (t > 1) t -= 1;
+			if (t < 1/6) return p + (q - p) * 6 * t;
+			if (t < 1/2) return q;
+			if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
+			return p;
+		}
+
+		var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+		var p = 2 * l - q;
+
+		r = hue_to_rgb(p, q, h + 1/3);
+		g = hue_to_rgb(p, q, h);
+		b = hue_to_rgb(p, q, h - 1/3);
+	}
+
+	r *= 255;
+	g *= 255;
+	b *= 255;
+
+	return [r, g, b];
+}
+
+function delta_e(rgb_a, rgb_b) {
+	var labA = rgb_to_lab(rgb_a[0], rgb_a[1], rgb_a[2]);
+	var labB = rgb_to_lab(rgb_b[0], rgb_b[1], rgb_b[2]);
+	var deltaL = labA[0] - labB[0];
+	var deltaA = labA[1] - labB[1];
+	var deltaB = labA[2] - labB[2];
+	var c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
+	var c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
+	var deltaC = c1 - c2;
+	var deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
+	deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
+	var sc = 1.0 + 0.045 * c1;
+	var sh = 1.0 + 0.015 * c1;
+	var deltaLKlsl = deltaL / (1.0);
+	var deltaCkcsc = deltaC / (sc);
+	var deltaHkhsh = deltaH / (sh);
+	var i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
+	return i < 0 ? 0 : Math.sqrt(i);
+}
+
+function rgb_to_lab(r,g,b){
+	var r = r / 255, g = g / 255, b = b / 255, x, y, z;
+	r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
+	g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
+	b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
+	x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
+	y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
+	z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
+	x = (x > 0.008856) ? Math.pow(x, 1/3) : (7.787 * x) + 16/116;
+	y = (y > 0.008856) ? Math.pow(y, 1/3) : (7.787 * y) + 16/116;
+	z = (z > 0.008856) ? Math.pow(z, 1/3) : (7.787 * z) + 16/116;
+	return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)];
+}
+
diff --git a/assets/webconfig/c/styles.css b/assets/webconfig/c/styles.css
new file mode 100644
index 00000000..f9398cd1
--- /dev/null
+++ b/assets/webconfig/c/styles.css
@@ -0,0 +1,201 @@
+* {
+	border: 0;
+	margin: 0;
+	padding: 0;
+	overflow: hidden;
+	outline: none;
+	background: none;
+	font-size: 0;
+	line-height: 0;
+}
+
+html, body {
+	background: #111;
+	color: fff;
+}
+
+#camera {
+	position: relative;
+}
+
+#wall,
+#tv {
+	position: absolute;
+	top: 50%;
+	width: 32px;
+	height: 332px;
+	border-radius: 8px;
+	border: 4px solid #fff;
+
+	transform: translate(-50%, -50%);
+
+	opacity: .5;
+}
+
+#tv {
+	left: 30%;
+	width: 136px;
+}
+
+#wall {
+	left: 70%;
+	width: 136px;
+	border-style: dotted;
+}
+
+#tv ins {
+	left: 40%;
+	height: 32px;
+}
+#tv ins#tv_white,
+#tv ins#tv_black {
+	left: calc(40% - 60px);
+	height: 332px;
+}
+#tv ins#tv_red {
+	top: 90px;
+}
+#tv ins#tv_green {
+	top: 150px;
+}
+#tv ins#tv_blue {
+	top: 210px;
+}
+#tv ins#tv_cyan {
+	top: 270px;
+}
+#tv ins#tv_magenta {
+	top: 330px;
+}
+#tv ins#tv_yellow {
+	top: 390px;
+}
+#tv ins#tv_black {
+	left: calc(40% - 120px);
+}
+
+.lock {
+	opacity: 1;
+}
+
+#calibration {
+	max-width: 640px;
+	margin: 0 auto;
+	position: relative;
+}
+#canvas {
+	display: block;
+
+	width: 640px;
+	height: 480px;
+	border-radius: 4px;
+	background: #333;
+}
+
+#source {
+	display: none;
+}
+
+#tv_color_led,
+#wall_color_led {
+	display: inline-block;
+	width: 50%;
+	height: 32px;
+	background: #222;
+
+	color: #fff;
+	text-transform: uppercase;
+	text-align: center;
+	font: normal 12px/32px Monospace;
+}
+
+#color_leds {
+	display: block;
+	height: 64px;
+}
+#color_leds ins {
+	width: calc(100% / 8);
+	display: inline-block;
+	height: 32px;
+}
+#color_leds ins#led_wall {
+	width: 100%;
+}
+
+#tv ins#tv_red {
+	border-color: red;
+}
+#tv ins#tv_green {
+	border-color: green;
+}
+#tv ins#tv_blue {
+	border-color: blue;
+}
+#tv ins#tv_cyan {
+	border-color: cyan;
+}
+#tv ins#tv_magenta {
+	border-color: magenta;
+}
+#tv ins#tv_yellow {
+	border-color: yellow;
+}
+#tv ins#tv_black {
+	border-color: black;
+}
+v
+#tv ins#tv_white {
+	border-color: white;
+}
+
+#tv_wall_devider {
+	position: absolute;
+	width: 0;
+	border-radius: 0;
+	border: 2px dashed #fff;
+	height: 100vh;
+	top: 0;
+	bottom: 0;
+	left: 50%;
+	opacity: .5;
+}
+
+#color_text {
+	display: inline-block;
+	font: normal 10px/24px Monospace;
+	color: #fff;
+
+	display: none;
+
+}
+
+button {
+	padding: 0 16px;
+	background: #666;
+	color: #fff;
+	text-transform: uppercase;
+	min-width: 60px;
+
+	font: normal 10px/24px Monospace;
+	margin: 8px 0;
+
+	transition: background .2s;
+}
+button.auto {
+	background: #aaa;
+}
+
+#controls {
+	align-items: baseline;
+	display: flex;
+	justify-content: space-between;
+}
+
+#calibrate_init {
+	margin-left: 0;
+}
+#calibrate_apply {
+	margin: 8px 0;
+	width: 100%;
+	padding: 0;
+}
\ No newline at end of file