diff --git a/index.html b/index.html
index ebbee8b..019819b 100644
--- a/index.html
+++ b/index.html
@@ -5,9 +5,6 @@
 	<script type="text/javascript" src="jquery-2.0.3.min.js"></script>
 	<script type="text/javascript" src="jquery.cookie.js"></script>
 	<script type="text/javascript" src="uhr.js"></script>
-	<script type="text/javascript" src="uhr-de_CH.js"></script>
-	<script type="text/javascript" src="uhr-de.js"></script>
-	<script type="text/javascript" src="uhr-en.js"></script>
 	<link rel="stylesheet" type="text/css" href="uhr.css" />
 	<link rel="stylesheet" type="text/css" href="uhr-black.css" id="theme" />
 	<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
@@ -35,7 +32,7 @@
 		<option value="en">English</option>
 	</select>
 	<div class="onoffswitch">
-		<input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="onoffswitch" checked="checked" onclick="updateClockState()" />
+		<input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="onoffswitch" checked="checked" onclick="uhr.toggle()" />
 		<label class="onoffswitch-label" for="onoffswitch">
 		    <div class="onoffswitch-inner"></div>
 		    <div class="onoffswitch-switch"></div>
@@ -43,12 +40,13 @@
 	</div>
 	<p id="disclaimer">Created by fritteli, inspired by <a href="http://www.qlocktwo.com/">QLOCKTWO</a>.
 	<script type="text/javascript">
+		var uhr = new Uhr($('#renderarea'), $('#theme'));
 		$(document).ready(function() {
 			$('#themeswitcher').on('change', function() {
-				switchTheme(this.value);
+				uhr.setTheme(this.value);
 			});
 			$('#layoutswitcher').on('change', function() {
-				switchLayout(this.value);
+				uhr.setLayout(this.value);
 			});
 			$.cookie.defaults.expires = 365;
 			$.cookie.defaults.path = '/';
@@ -65,20 +63,21 @@
 				status = 'on';
 			}
 			$('#themeswitcher').val(theme);
-			switchTheme(theme);
+			uhr.setTheme(theme);
 			$('#layoutswitcher').val(layout);
-			switchLayout(layout);
+			uhr.setLayout(layout);
 			if (status == 'on') {
-				if(!isOn()) {
-					$('#onoffswitch').click();
-				}
+				uhr.start();
+				$('#onoffswitch').prop('checked', true);
 			} else {
-				if(isOn()) {
-					$('#onoffswitch').click();
-				}
+				uhr.stop();
+				$('#onoffswitch').prop('checked', false);
 			}
 		});
 	</script>
+	<script type="text/javascript" src="uhr-de_CH.js"></script>
+	<script type="text/javascript" src="uhr-de.js"></script>
+	<script type="text/javascript" src="uhr-en.js"></script>
 </body>
 </html>
 
diff --git a/manifest.appcache b/manifest.appcache
index 311ef39..acee32a 100644
--- a/manifest.appcache
+++ b/manifest.appcache
@@ -1,5 +1,5 @@
 CACHE MANIFEST
-# 2.1.4
+# 2.2
 
 index.html
 jquery-2.0.3.min.js
@@ -17,4 +17,3 @@ uhr-white.css
 uhr.css
 uhr.js
 uhr.woff
-
diff --git a/uhr-de.js b/uhr-de.js
index 1e18378..dc7470e 100644
--- a/uhr-de.js
+++ b/uhr-de.js
@@ -1,4 +1,4 @@
-layout['de'] = {
+var layout = {
 	language: 'Deutsch',
 	values: [
 		[l('E', 'on'), l('S', 'on'),l('K'),l('I', 'on'),l('S', 'on'),l('T', 'on'),l('A'),m('F', 5, 25, 35, 55),m('Ü', 5, 25, 35, 55),m('N', 5, 25, 35, 55),m('F', 5, 25, 35, 55)],
@@ -13,3 +13,4 @@ layout['de'] = {
 		[h('Z', 10), h('E', 10),h('H', 10),h('N', 9, 10),h('E', 9),h('U', 9),h('N', 9),l('K'),l('U'),l('H'),l('R')]
 	]
 };
+uhr.register('de', layout);
diff --git a/uhr-de_CH.js b/uhr-de_CH.js
index 1246779..83bdd4f 100644
--- a/uhr-de_CH.js
+++ b/uhr-de_CH.js
@@ -1,4 +1,4 @@
-layout['de_CH'] = {
+var layout = {
 	language: 'Bärndütsch',
 	values: [
 		[l('E', 'on'), l('S', 'on'),l('K'),l('I', 'on'),l('S', 'on'),l('C', 'on'),l('H', 'on'),l('A'),m('F', 5, 25, 35, 55),m('Ü', 5, 25, 35, 55),m('F', 5, 25, 35, 55)],
@@ -13,3 +13,4 @@ layout['de_CH'] = {
 		[h('Z', 12), h('W', 12),h('Ö', 12),h('U', 12),h('F', 12),h('I', 12),l('N'),l('A'),l('U'),l('H'),l('R')]
 	]
 };
+uhr.register('de_CH', layout);
diff --git a/uhr-en.js b/uhr-en.js
index 8a22458..83b95fc 100644
--- a/uhr-en.js
+++ b/uhr-en.js
@@ -1,4 +1,4 @@
-layout['en'] = {
+var layout = {
 	language: 'English',
 	values: [
 		[l('I', 'on'), l('T', 'on'),l('L'),l('I', 'on'),l('S', 'on'),l('B'),l('F'),l('A'),l('M'),l('P'),l('M')],
@@ -13,3 +13,4 @@ layout['en'] = {
 		[h('T', 10), h('E', 10),h('N', 10),l('S'),l('E'),l('O', 'sharphour'),l('C', 'sharphour'),l('L', 'sharphour'),l('O', 'sharphour'),l('C', 'sharphour'),l('K', 'sharphour')]
 	]
 };
+uhr.register('en', layout);
diff --git a/uhr.js b/uhr.js
index 4f74a1c..c98a2d0 100644
--- a/uhr.js
+++ b/uhr.js
@@ -1,35 +1,102 @@
-var clock = null;
-var currentMinute = -1;
-var layout = new Array();
-layout['default'] = {
-	language: 'Undefined',
-	values: []
-};
-var currentLayout = layout['default'];
+/**
+ * Die Uhr.
+ * @param renderarea   Das jQuery-gewrappte HTML-Element, auf dem die Uhr angezeigt werden soll.
+ * @param themeElement Das HTML-Stylesheet-Tag, das das Theme-CSS referenziert.
+ */
+function Uhr(renderarea, themeElement) {
+	this.renderarea = renderarea;
+	this.themeElement = themeElement;
+	this.timer = null;
+	this.currentTheme = null;
+	this.currentLayout = null;
+	this.layouts = new Array();
+	this.currentMinute = -1;
+	this.register('undefined', {
+		language: 'Undefined',
+		values: []
+	});
+}
 
-function highlightCurrentTime() {
-	var now = new Date();
-	var dotMinute = getDotMinute(now);
-	if (dotMinute == currentMinute) {
-		return;
-	}
-	currentMinute = dotMinute;
-	var hour = getHour(now);
-	var coarseMinute = getCoarseMinute(now);
-	resetItems();
-	for (var i = 1; i <= dotMinute; i++) {
-		highlight('dot' + i);
-	}
-	highlight('minute' + coarseMinute);
-	hour = normalizeHour(hour);
-	highlight('hour' + hour);
-	if (coarseMinute == 0) {
-		highlight('sharphour');
+Uhr.prototype.toggle = function() {
+	if (this.isOn()) {
+		this.stop();
+	} else {
+		this.start();
 	}
 }
-function getHour(date) {
-	if (typeof currentLayout.getHour === 'function') {
-		return currentLayout.getHour(date);
+Uhr.prototype.start = function() {
+	if (!this.isOn()) {
+		var uhr = this;
+		this.timer = window.setInterval(function() {uhr.update();}, 1000);
+		this.update();
+		$.cookie('status', 'on');
+	}
+}
+Uhr.prototype.stop = function() {
+	if (this.isOn()) {
+		window.clearInterval(this.timer);
+		this.timer = null;
+		this.update();
+		$.cookie('status', 'off');
+	}
+}
+Uhr.prototype.isOn = function() {
+	return this.timer != null;
+}
+Uhr.prototype.register = function(key, layout) {
+	this.layouts[key] = layout;
+}
+Uhr.prototype.setLayout = function(locale) {
+	var newLayout = this.layouts[locale];
+	if (newLayout !== undefined && newLayout != this.currentLayout) {
+		this.currentLayout = newLayout;
+		var renderer = new UhrRenderer(this.currentLayout, this.renderarea);
+		renderer.render(this);
+		$.cookie('layout', locale);
+	}
+}
+Uhr.prototype.setTheme = function(theme) {
+	if (theme != this.currentTheme) {
+		this.currentTheme = theme;
+		this.themeElement.attr('href', 'uhr-' + theme + '.css');
+		$.cookie('theme', theme);
+	}
+}
+Uhr.prototype.update = function() {
+	if (this.isOn()) {
+		var now = new Date();
+		var dotMinute = this.getDotMinute(now);
+		if (dotMinute == this.currentMinute) {
+			return;
+		}
+		this.currentMinute = dotMinute;
+		var hour = this.getHour(now);
+		var coarseMinute = this.getCoarseMinute(now);
+		this.clear();
+		this.highlight('on');
+		for (var i = 1; i <= dotMinute; i++) {
+			this.highlight('dot' + i);
+		}
+		this.highlight('minute' + coarseMinute);
+		hour = this.normalizeHour(hour);
+		this.highlight('hour' + hour);
+		if (coarseMinute == 0) {
+			this.highlight('sharphour');
+		}
+	} else {
+		this.clear();
+		this.currentMinute = -1;
+	}
+}
+Uhr.prototype.clear = function() {
+	this.renderarea.find('.item').removeClass('active');
+}
+Uhr.prototype.highlight = function(itemClass) {
+	this.renderarea.find('.item.' + itemClass).addClass('active');
+}
+Uhr.prototype.getHour = function(date) {
+	if (typeof this.currentLayout.getHour === 'function') {
+		return this.currentLayout.getHour(date);
 	}
 	var hour = date.getHours();
 	if (date.getMinutes() >= 25) {
@@ -37,31 +104,21 @@ function getHour(date) {
 	}
 	return hour;
 }
-function getCoarseMinute(date) {
-	if (typeof currentLayout.getCoarseMinute === 'function') {
-		return currentLayout.getCoarseMinute(date);
+Uhr.prototype.getCoarseMinute = function(date) {
+	if (typeof this.currentLayout.getCoarseMinute === 'function') {
+		return this.currentLayout.getCoarseMinute(date);
 	}
 	var minutes = date.getMinutes();
-	return minutes - getDotMinute(date);
+	return minutes - this.getDotMinute(date);
 }
-function getDotMinute(date) {
-	if (typeof currentLayout.getDotMinute === 'function') {
-		return currentLayout.getDotMinute(date);
+Uhr.prototype.getDotMinute = function(date) {
+	if (typeof this.currentLayout.getDotMinute === 'function') {
+		return this.currentLayout.getDotMinute(date);
 	}
 	var minutes = date.getMinutes();
 	return minutes % 5;
 }
-function clearDisplay() {
-	$('.item').removeClass('active');
-}
-function resetItems() {
-	clearDisplay()
-	highlight('on');
-}
-function highlight(itemClass) {
-	$('.item.' + itemClass).addClass('active');
-}
-function normalizeHour(hour) {
+Uhr.prototype.normalizeHour = function(hour) {
 	if (hour > 12) {
 		hour %= 12;
 	}
@@ -70,73 +127,52 @@ function normalizeHour(hour) {
 	}
 	return hour;
 }
-function startClock() {
-	if (clock == null) {
-		highlightCurrentTime();
-		clock = window.setInterval(highlightCurrentTime, 1000);
-	}
-	$.cookie('status', 'on');
+
+/**
+ * Hilfsklasse zum Rendern der Uhr.
+ * @param layout     Layout-Objekt, das gerendert werden soll.
+ * @param renderarea Das jQuery-gewrappte HTML-Element, auf dem gerendert werden soll.
+ */
+function UhrRenderer(layout, renderarea) {
+	this.layout = layout;
+	this.renderarea = renderarea;
 }
-function stopClock() {
-	if (clock != null) {
-		window.clearInterval(clock);
-		clock = null;
-		currentMinute = -1;
-		clearDisplay();
-	}
-	$.cookie('status', 'off');
-}
-function updateClockState() {
-	if (isOn()) {
-		startClock();
-	} else {
-		stopClock();
-	}
-}
-function isOn() {
-	return $('#onoffswitch').is(':checked');
-}
-function switchTheme(theme) {
-	$('#theme').attr('href', 'uhr-' + theme + '.css');
-	$.cookie('theme', theme);
-}
-function switchLayout(locale) {
-	stopClock();
-	currentLayout = layout[locale];
-	if (currentLayout == undefined) {
-		currentLayout = layout['default'];
-	}
-	renderLayout();
-	if (isOn()) {
-		startClock();
-	}
-	$.cookie('layout', locale);
-}
-function renderLayout() {
-	var container = $('#renderarea');
-	container.empty();
-	for (var y = 0; y < currentLayout.values.length; y++) {
-		for (var x = 0; x < currentLayout.values[y].length; x++) {
-			var letter = currentLayout.values[y][x];
-			container.append(letter.toString());
+UhrRenderer.prototype.render = function(uhr) {
+	var renderer = this;
+	this.renderarea.fadeOut('fast', function() {
+		renderer.renderarea.empty();
+		for (var y = 0; y < renderer.layout.values.length; y++) {
+			for (var x = 0; x < renderer.layout.values[y].length; x++) {
+				var letter = renderer.layout.values[y][x];
+				renderer.renderarea.append(letter.toString());
+			}
+			if (y < renderer.layout.values.length - 1) {
+				renderer.renderarea.append('<br/>');
+			}
 		}
-		if (y < currentLayout.values.length - 1) {
-			container.append('<br/>');
-		}
-	}
+		uhr.currentMinute = -1;
+		uhr.update();
+		renderer.renderarea.fadeIn('fast');
+	});
 }
+
+/**
+ * Ein Buchstabe. Hilfsklasse für den Renderer und Inhalt der Layout-Arrays.
+ * @param value Der Buchstabe, der Dargestellt werden soll.
+ * @param style Die CSS-Styleklassen des Buchstabens.
+ */
 function Letter(value, style) {
 	this.value = value;
 	this.style = style || '';
 	this.getStyle = function() {
-		return "item letter " + style;
+		return 'item letter ' + style;
 	}
 	this.getValue = function() {
 		return value;
 	}
 }
 Letter.prototype.toString = function letterToString() {
-	return "<span class=\"" + this.getStyle() + "\">" + this.getValue() + "</span>";
+	return '<span class="' + this.getStyle() + '">' + this.getValue() + '</span>';
 }
 /**
  * Hilfsfunktion, um einen Buchstaben zu erzeugen.