diff --git a/VERSION b/VERSION
index 1cc9c180e266a183d615bbbb1b28f7ca520254d5..dc1e644a1014338ad0ca67b5c0bfbd2402e761ee 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.5.8
+1.6.0
diff --git a/generator/static/images/examples/komise.png b/generator/static/images/examples/komise.png
new file mode 100644
index 0000000000000000000000000000000000000000..2f326baac3e309320c6047be4ae4ff1ef02749ef
Binary files /dev/null and b/generator/static/images/examples/komise.png differ
diff --git a/generator/static/images/examples/komise_story.png b/generator/static/images/examples/komise_story.png
new file mode 100644
index 0000000000000000000000000000000000000000..150bc6a2ce6edfe88bd6a2a8cc1fd665a9def447
Binary files /dev/null and b/generator/static/images/examples/komise_story.png differ
diff --git a/generator/static/js/templates/komise-story.js b/generator/static/js/templates/komise-story.js
new file mode 100644
index 0000000000000000000000000000000000000000..51d838ce12b56bcf6f59a0d3c39a487bca40808b
--- /dev/null
+++ b/generator/static/js/templates/komise-story.js
@@ -0,0 +1,823 @@
+class KomiseStory extends Template {
+	description = "Určeno pro story na sociální sítě.";
+	
+	changeableAttributes = [
+		"logoImage",
+		"primaryImage",
+		"primaryText",
+		"secondaryText",
+		"primaryColorScheme",
+		"primaryImagePosition",
+		"iconImage"
+	];
+
+	primaryColorSchemes = [
+		"black-on-white",
+		"white-on-black"
+	];
+	
+	primaryTextHighlightColorSchemes = [
+		"black-on-gold"
+	];
+	
+	changeableColors = [
+		"primaryTextColor",
+		"foregroundColor",
+		"primaryTextHighlightColor",
+		"requesterTextColor"
+	];
+	
+	lightLogoDefaultSource = "/static/images/badges/default-dark.png";
+	darkLogoDefaultSource = "/static/images/badges/default-light.png";
+	
+	iconImage = null;
+	iconSource = "";
+	
+	aspectRatio = 0.5625;
+	defaultResolution = 1920;
+	
+	secondaryText = "";
+
+	// Canvas
+	async redrawCanvas() {
+		if (this.redrawing) {
+			return;
+		}
+
+		this.redrawing = true;
+		
+		const primaryRectangleAngle = Math.ceil(this.canvas.height * 0.015);
+		const primaryRectanglePaddingBottom = Math.ceil(this.canvas.height * 0.04);
+		const primaryRectanglePaddingTop = 0;
+		const primaryRectangleAdditionalPaddingWithDiacritics = Math.ceil(this.canvas.height * 0.01);
+		const primaryRectanglePaddingSides = Math.ceil(this.canvas.width * 0.05);
+
+		const highlightPaddingSides = Math.ceil(this.canvas.width * 0.01);
+		const highlightPaddingBottom = Math.ceil(this.canvas.height * 0.0125);
+		const highlightPaddingTop = Math.ceil(this.canvas.height * -0.01); // It is, it's how Roboto works.
+
+		const logoHeight = Math.ceil(this.canvas.height * 0.075) * this.logoImageZoom;
+		const logoBottomOffset = Math.ceil(this.canvas.height * 0.1) - (
+			logoHeight / this.logoImageZoom * (this.logoImageZoom - 1) / 2
+		);
+		
+		let primaryFontSize = Math.ceil(this.canvas.height * 0.075);
+		const primaryFontLinePadding = 0;
+		const primaryTextMaxLines = 3;
+		const primaryTextPaddingBottom = Math.ceil(this.canvas.height * 0.17);
+		
+		let secondaryFontSize = Math.ceil(this.canvas.height * 0.06);
+		const secondaryTextPaddingBottom = Math.ceil(this.canvas.height * 0.04);
+		
+		const iconImageOffsetBottom = Math.ceil(this.canvas.height * 0.1);
+		const iconImageOffsetTop = Math.ceil(this.canvas.height * 0.03);
+		const iconOpacity = 0.125;
+		
+		// Get primary text split into lines, no more than ``primaryTextMaxLines`` of them
+		
+		let primaryTextLines = null;
+		
+		do {
+			this.context.font = `${this.primaryFontStyle} ${primaryFontSize}px ${this.primaryFont}`;
+
+			primaryTextLines = splitStringIntoLines(
+				this.context,
+				this.primaryText,
+				this.canvas.width - primaryRectanglePaddingSides * 2,
+				primaryTextMaxLines,
+				true
+			).reverse();
+
+			if (primaryTextLines.length > primaryTextMaxLines) {
+				primaryFontSize -= 2;
+			}
+		} while (primaryTextLines.length > primaryTextMaxLines);
+
+		// Clear the canvas
+		this.context.clearRect(
+			0, 0,
+			this.canvas.width, this.canvas.height
+		);
+		
+		// Set image
+		if (this.primaryImage !== null) {
+			// https://github.com/DonkeyDushan/piratilol/blob/main/src/js/index.js
+			// Thanks to DonkeyDushan, the guy who made the joke 2021 campaign generator :D
+
+			const imageScaleX = this.canvas.width / this.primaryImage.width;
+			const imageScaleY = this.canvas.height / this.primaryImage.height;
+
+			const imageScale = Math.max(imageScaleX, imageScaleY) * this.primaryImageZoom;
+			
+			// https://stackoverflow.com/a/8529655
+			// Thanks to alex!
+			this.context.setTransform(
+				imageScale,
+				0, 0,
+				imageScale,
+				(this.canvas.width - this.primaryImage.width * imageScale) / 2 + this.primaryImageX * this.primaryImageZoom,
+				(this.canvas.height - this.primaryImage.height * imageScale) / 2 + this.primaryImageY * this.primaryImageZoom
+			);
+			this.context.drawImage(
+				this.primaryImage,
+				0, 0
+			);
+			this.context.setTransform(); // Reset transformation
+		}
+		
+		const firstPrimaryLine = primaryTextLines[primaryTextLines.length - 1].join(" ");
+		
+		// Create rectangle behind the primary text
+		const primaryRectangleHeight = (
+			primaryTextLines.length * (primaryFontSize + primaryFontLinePadding)
+			+ primaryRectanglePaddingTop
+			+ primaryRectanglePaddingBottom
+			+ primaryTextPaddingBottom
+			+ (
+				(
+					firstPrimaryLine.replace(/[a-zA-Z0-9À-ž]+/g, "").length
+					!== firstPrimaryLine.replace(/[a-zA-Z0-9]+/g, "").length
+				) ?
+				primaryRectangleAdditionalPaddingWithDiacritics :
+				0
+			)
+		);
+		
+		const classRef = this;
+		
+		// Create background gradient
+		const gradientLoadPromise = new Promise(
+			resolve => {
+				const gradientImage = new Image();
+				
+				gradientImage.onload = function() {
+					classRef.context.drawImage(
+						this,
+						0, 0,
+						classRef.canvas.width, classRef.canvas.height - primaryRectangleHeight
+					);
+					
+					resolve();
+				}
+				
+				gradientImage.src = "static/images/gradient.png";
+			}
+		);
+		
+		await gradientLoadPromise;
+		
+		if (this.secondaryText !== "") {
+			this.context.textAlign = "center";
+			this.context.font = `${secondaryFontSize}px ${this.primaryFont}`;
+			
+			while (
+				this.context.measureText(this.secondaryText).width
+				> (this.canvas.width - 2 * primaryRectanglePaddingSides)
+			) {
+				secondaryFontSize -= 2;
+				this.context.font = `${secondaryFontSize}px ${this.primaryFont}`;
+			}
+			
+			this.context.fillStyle = this.secondaryTextColor;
+			
+			this.context.fillText(
+				this.secondaryText,
+				this.canvas.width / 2, this.canvas.height - primaryRectangleHeight - secondaryTextPaddingBottom
+			);
+		}
+		
+		this.context.font = `${this.primaryFontStyle} ${primaryFontSize}px ${this.primaryFont}`;
+		
+		const foregroundRGB = hexToRgb(this.foregroundColor);
+		const foregroundLightness = (
+			0.2126 * foregroundRGB.r
+			+ 0.7152 * foregroundRGB.g
+			+ 0.0722 * foregroundRGB.b
+		)
+		
+		this.context.beginPath();
+		
+		const primaryRectangleStartingX = 0;
+		const primaryRectangleEndingX = this.canvas.width;
+		
+		this.context.fillStyle = this.foregroundColor;
+		
+		this.context.moveTo(
+			0,
+			this.canvas.height
+		);
+		this.context.lineTo(
+			this.canvas.width,
+			this.canvas.height
+		);
+		this.context.lineTo(
+			this.canvas.width,
+			this.canvas.height - primaryRectangleHeight - primaryRectangleAngle
+		);
+		this.context.lineTo(
+			0,
+			this.canvas.height - primaryRectangleHeight
+		);
+		
+		this.context.closePath();
+		
+		this.context.fill();
+		
+		function drawIconImage(image) {
+			const iconHeight = primaryRectangleHeight - iconImageOffsetBottom - iconImageOffsetTop;
+			const iconWidth = (image.width * (iconHeight / image.height));
+			
+			classRef.context.globalAlpha = iconOpacity;
+			
+			const primaryTextRGB = hexToRgb(classRef.primaryTextColor);
+			
+			classRef.context.drawImage(
+				colorizeImage(
+					image,
+					iconWidth, iconHeight,
+					primaryTextRGB.r,
+					primaryTextRGB.g,
+					primaryTextRGB.b
+				),
+				(classRef.canvas.width - iconWidth) / 2, classRef.canvas.height - iconImageOffsetBottom - iconHeight,
+				iconWidth, iconHeight
+			);
+			
+			classRef.context.globalAlpha = 1;
+		}
+		
+		// Create icon, if there is one
+		if (this.iconImage !== null) {
+			drawIconImage(this.iconImage);
+		} else if (this.iconSource !== null) {
+			const iconImageLoadPromise = new Promise(
+				resolve => {
+					const iconImage = new Image();
+					
+					iconImage.onload = function() {
+						drawIconImage(this);
+						
+						resolve();
+					}
+					
+					iconImage.src = this.iconSource;
+				}
+			);
+			
+			await iconImageLoadPromise;
+		}
+		
+		// Create primary text
+		this.context.textAlign = "left";
+		
+		const useLightHighlightAndUseDarkLogo = (foregroundLightness > 207);
+		
+		const primaryLineX = this.canvas.width / 2;
+		let currentPrimaryLineY = (
+			this.canvas.height
+			- primaryRectanglePaddingBottom
+			- primaryFontLinePadding
+			- primaryTextPaddingBottom
+		);
+		
+		let primaryTextHighlightedColor = null;
+		
+		const lowercasePrimaryTextHighlightColor = this.primaryTextHighlightColor.toLowerCase();
+		const hasColorOverride = (
+			lowercasePrimaryTextHighlightColor === "#209a37" ||
+			lowercasePrimaryTextHighlightColor === "#e63812"
+		);
+		
+		if (hasColorOverride) {
+			if (useLightHighlightAndUseDarkLogo) {
+				primaryTextHighlightedColor = this.foregroundColor;
+			} else {
+				primaryTextHighlightedColor = this.primaryTextColor;
+			}
+		} else if (!useLightHighlightAndUseDarkLogo) {
+			primaryTextHighlightedColor = this.foregroundColor;
+		} else {
+			primaryTextHighlightedColor = this.primaryTextColor;
+		}
+		
+		this.context.fillStyle = this.primaryTextColor;
+		
+		for (let line of primaryTextLines) {
+			let wordPosition = 0;
+			
+			for (let word of line) {
+				const previousWords = line.slice(0, wordPosition).join(" ");
+				const previousWordsWidth = this.context.measureText(
+					previousWords
+					+ (
+						(previousWords.length !== 0) ?
+						" " : ""
+					)
+				).width;
+				
+				const nextWords = line.slice(wordPosition + 1, line.length).join(" ")
+				const nextWordsWidth = this.context.measureText(
+					nextWords
+					+ (
+						(nextWords.length !== 0) ?
+						" " : ""
+					)
+				).width;
+				
+				let currentWordWidth = this.context.measureText(word).width;
+				
+				for (const word of line.slice(wordPosition + 1, line.length)) {
+					if (word.isHighlighted) {
+						currentWordWidth += this.context.measureText(word.toString() + " ").width;
+					} else {
+						break;
+					}
+				}
+				
+				if (word.isHighlighted) {
+					if (
+						wordPosition === 0 ||
+						!line[wordPosition - 1].isHighlighted
+					) {
+						this.context.fillStyle = this.primaryTextHighlightColor;
+						this.context.beginPath();
+						
+						const startingHighlightLineX = (
+							primaryLineX
+							+ Math.ceil(previousWordsWidth / 2)
+							- Math.ceil(nextWordsWidth / 2)
+							- Math.ceil(this.context.measureText(word).width / 2)
+						);
+						
+						this.context.moveTo(
+							startingHighlightLineX - highlightPaddingSides,
+							currentPrimaryLineY + highlightPaddingBottom
+						);
+						this.context.lineTo(
+							(
+								startingHighlightLineX
+								+ currentWordWidth
+								+ highlightPaddingSides
+							),
+							(
+								currentPrimaryLineY
+								+ highlightPaddingBottom
+								- Math.max(
+									(currentWordWidth * primaryRectangleAngle)
+									/ (this.canvas.width - 2 * primaryRectanglePaddingSides)
+								)
+							)
+						);
+						this.context.lineTo(
+							(
+								startingHighlightLineX
+								+ currentWordWidth
+								+ highlightPaddingSides
+							),
+							(
+								currentPrimaryLineY
+								- primaryFontSize
+								- highlightPaddingTop
+								- Math.max(
+									(currentWordWidth * primaryRectangleAngle)
+									/ (this.canvas.width - 2 * primaryRectanglePaddingSides)
+								)
+							)
+						);
+						this.context.lineTo(
+							startingHighlightLineX - highlightPaddingSides,
+							(
+								currentPrimaryLineY
+								- primaryFontSize
+								- highlightPaddingTop
+							)
+						);
+						
+						this.context.closePath();
+						
+						this.context.fill();
+					}
+					
+					this.context.fillStyle = primaryTextHighlightedColor;
+				}
+				
+				this.context.fillText(
+					word + " ",
+					(
+						primaryLineX
+						+ Math.ceil(previousWordsWidth / 2)
+						- Math.ceil(nextWordsWidth / 2)
+						- Math.ceil(this.context.measureText(word).width / 2)
+					),
+					currentPrimaryLineY
+				);
+				
+				wordPosition++;
+				
+				this.context.fillStyle = this.primaryTextColor;
+			}
+			
+			currentPrimaryLineY -= (primaryFontSize + primaryFontLinePadding);
+		}
+		
+		function drawLogoImage(image) {
+			const logoWidth = Math.ceil(image.width * (logoHeight / image.height));
+
+			classRef.context.drawImage(
+				image,
+				(classRef.canvas.width - logoWidth) / 2, classRef.canvas.height - logoHeight - logoBottomOffset,
+				logoWidth, logoHeight
+			);
+		}
+
+		if (this.logoImage === null) {
+			const logoImageLoadPromise = new Promise(
+				resolve => {
+					let logoImage = new Image();
+					
+					logoImage.onload = function() {
+						drawLogoImage(this);
+						
+						resolve();
+					}
+					
+					if (!useLightHighlightAndUseDarkLogo) {
+						logoImage.src = classRef.lightLogoDefaultSource;
+					} else {
+						logoImage.src = classRef.darkLogoDefaultSource;
+					}
+				}
+			);
+			
+			await logoImageLoadPromise;
+		} else {
+			drawLogoImage(this.logoImage);
+		}
+		
+		if (this.requesterText !== "") {
+			// https://newspaint.wordpress.com/2014/05/22/writing-rotated-text-on-a-javascript-canvas/
+			// Thanks to newspaint!
+			
+			this.context.save();
+
+			this.context.translate(this.canvas.width - 1, 0);
+
+			this.context.rotate(3 * Math.PI / 2);
+
+			let requesterFontSize = Math.ceil(this.canvas.width * 0.0175);
+			
+			do {
+				this.context.font = `${this.primaryFontStyle} ${requesterFontSize}px ${this.primaryFont}`;
+				
+				if (
+					this.context.measureText(this.requesterText).width
+					> primaryRectangleHeight - (this.canvas.height * 0.03)
+				) {
+					requesterFontSize -= 2;
+					this.context.font = `${this.primaryFontStyle} ${requesterFontSize}px ${this.primaryFont}`;
+				}
+			} while (
+				this.context.measureText(this.requesterText).width
+				> primaryRectangleHeight - (this.canvas.height * 0.03)
+			);
+			
+			this.context.fillStyle = this.requesterTextColor;
+
+			this.context.textAlign = "left";
+
+			this.context.globalAlpha = 0.6;
+			this.context.fillText(
+				this.requesterText,
+				-this.canvas.height * 0.985, -this.canvas.width * 0.99 + requesterFontSize
+			);
+			this.context.globalAlpha = 1;
+			
+			this.context.restore();
+		}
+		this.finalDrawHook();
+		this.stickerDrawHook();
+		
+		this.redrawing = false;
+	}
+	
+	// Text
+	async setSecondaryText(text, skipRedraw = false) {
+		this.secondaryText = text;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	// Icon
+	async setIconSource(url, skipRedraw = false) {
+		this.iconSource = url;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async setIconImageFromInput(imageInput, skipRedraw = false) {
+		if (imageInput.files.length == 0) {
+			return;
+		}
+		
+		const readPromise = new Promise(
+			resolve => {
+				const fileReader = new FileReader();
+				
+				let classRef = this;
+				
+				fileReader.onloadend = function(event) {
+					classRef.iconImage = new Image();
+					
+					classRef.iconImage.onload = function() {
+						if (!skipRedraw) {
+							classRef.redrawCanvas();
+						}
+						
+						resolve();
+					}
+					
+					classRef.iconImage.src = event.target.result;
+				}
+				
+				fileReader.readAsDataURL(imageInput.files[0]);
+			}
+		);
+		
+		await readPromise;
+	}
+	
+	async resetIconImage(skipRedraw = false) {
+		this.iconImage = null;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	// Color schemes
+	async setPrimaryColorScheme(scheme, skipRedraw = false) {
+		switch (scheme) {
+			case "black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "white-on-black":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor ="#000000";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "forum-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "forum-white-on-purple":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#962a51";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "zeleni-volary-bystrc-most-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "zeleni-volary-bystrc-most-white-on-green":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#00ad43";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "spolecne-s-piraty-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "spolecne-s-piraty-white-on-blue":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#21274e";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "louny-spolecne-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "louny-spolecne-white-on-purple":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#3e2a5b";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "litomerice-blue-on-white":
+				this.primaryTextColor = "#123172";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("litomerice", true);
+				
+				break;
+			case "litomerice-white-on-blue":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#123172";
+				
+				this.setPrimaryTextHighlightColorScheme("litomerice", true);
+				
+				break;
+			case "stranane-gray-on-yellow":
+				this.primaryTextColor = "#4d4d4d";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				
+				break;
+			case "stranane-yellow-on-white":
+				this.primaryTextColor = "#4d4d4d";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				this.primaryTextHighlightColor = "#4d4d4d";
+				
+				break;
+			case "stranane-white-on-yellow":
+				this.primaryTextColor = "#4d4d4d";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#ffd500";
+				
+				break;
+			case "prusanky-black-on-yellow":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				
+				break;
+			case "prusanky-yellow-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				this.primaryTextHighlightColor = "#000000";
+				
+				break;
+			case "prusanky-white-on-yellow":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#ffd500";
+				
+				break;
+			case "ujezd-green-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#8ed4a3";
+				this.primaryTextHighlightColor = "#ffdd55";
+				
+				break;
+			case "ujezd-white-on-green":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#8ed4a3";
+				
+				break;
+			case "cssd-red-on-black":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#e63812";
+				
+				break;
+			case "cssd-black-on-red":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#000000";
+				
+				break;
+			case "jilemnice-purple-on-black":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#6e1646";
+				
+				break;
+			case "jilemnice-black-on-purple":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#000000";
+				
+				break;
+			case "novarole-white-on-green":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#a9ce2d";
+				
+				break;
+			case "novarole-green-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#a9ce2d";
+				
+				this.primaryTextHighlightColor = "#ffeda5";
+				
+				break;
+			case "novarole-green-on-black":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#a9ce2d";
+				
+				this.primaryTextHighlightColor = "#ffeda5";
+				
+				break;
+			case "zeleni-melnik-yellow-name-rect":
+				await this.setPrimaryColorScheme("white-on-black", true);
+				
+				break;
+			default:
+				throw new Error("This scheme does not exist.");
+				break;
+		}
+		
+		this.requesterTextColor = this.primaryTextColor;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+
+	async setPrimaryTextHighlightColorScheme(scheme, skipRedraw = false) {
+		switch(scheme) {
+			case "gold":
+				this.primaryTextHighlightColor = "#ffeda5";
+				break;
+			case "litomerice":
+				this.primaryTextHighlightColor = "#afe87e";
+				break;
+			default:
+				throw new Error("This scheme does not exist.");
+				break;
+		}
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async setPrimaryTextHighlightColor(color, skipRedraw = false) {
+		this.primaryTextHighlightColor = color;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async loadData(
+		primaryImageInput = null,
+		primaryText = "",
+		nameText = "",
+		primaryColorScheme = "",
+		resultion = 2000,
+		skipRedraw = false
+	) {
+		await super.loadData(
+			primaryImageInput,
+			primaryText,
+			nameText,
+			primaryColorScheme,
+			resultion,
+			skipRedraw
+		);
+		
+		$("#icon-image-selection").val("Otevřená radnice 1");
+		$("#icon-image-selection").trigger("change");
+	}
+}
diff --git a/generator/static/js/templates/komise.js b/generator/static/js/templates/komise.js
new file mode 100644
index 0000000000000000000000000000000000000000..cecbdbd6f7262ebc8976497ed915d99061089655
--- /dev/null
+++ b/generator/static/js/templates/komise.js
@@ -0,0 +1,889 @@
+class Komise extends Template {
+	description = "Určeno pro sociální sítě.";
+	
+	changeableAttributes = [
+		"logoImage",
+		"logoIsCenter",
+		"primaryImage",
+		"primaryText",
+		"secondaryText",
+		"nameText",
+		"underNameText",
+		"primaryColorScheme",
+		"primaryImagePosition",
+		"iconImage"
+	];
+
+	primaryColorSchemes = [
+		"black-on-white",
+		"white-on-black"
+	];
+	
+	primaryTextHighlightColorSchemes = [
+		"black-on-gold"
+	];
+	
+	changeableColors = [
+		"primaryTextColor",
+		"foregroundColor",
+		"primaryTextHighlightColor",
+		"requesterTextColor"
+	];
+	
+	iconImage = null;
+	iconSource = "";
+	
+	logoIsCenter = false;
+	
+	aspectRatio = 1;
+	defaultResolution = 2000;
+	
+	secondaryText = "";
+	underNameText = "";
+
+	// Canvas
+	async redrawCanvas() {
+		if (this.redrawing) {
+			return;
+		}
+
+		this.redrawing = true;
+		
+		const primaryRectangleAngle = Math.ceil(this.canvas.height * 0.015);
+		const primaryRectanglePaddingBottom = Math.ceil(this.canvas.height * 0.01);
+		const primaryRectanglePaddingTop = 0;
+		const primaryRectangleAdditionalPaddingWithDiacritics = Math.ceil(this.canvas.height * 0.01);
+		const primaryRectanglePaddingSides = Math.ceil(this.canvas.width * 0.1);
+
+		const highlightPaddingSides = Math.ceil(this.canvas.width * 0.01);
+		const highlightPaddingBottom = Math.ceil(this.canvas.height * 0.0125);
+		const highlightPaddingTop = Math.ceil(this.canvas.height * -0.01); // It is, it's how Roboto works.
+
+		const logoHeight = Math.ceil(this.canvas.height * 0.055) * this.logoImageZoom;
+		const logoBottomOffset = Math.ceil(this.canvas.height * 0.06) - (
+			logoHeight / this.logoImageZoom * (this.logoImageZoom - 1) / 2
+		);
+		
+		const logoTextOffsetSide = Math.ceil(this.canvas.width * 0.1);
+		
+		const nameTextOffsetBottom = Math.ceil(this.canvas.height * 0.08);
+		
+		let primaryFontSize = Math.ceil(this.canvas.height * 0.13);
+		const primaryFontLinePadding = 0;
+		const primaryTextMaxLines = 3;
+		const primaryTextPaddingBottom = Math.ceil(this.canvas.height * 0.17);
+		
+		let secondaryFontSize = Math.ceil(this.canvas.height * 0.06);
+		const secondaryTextPaddingBottom = Math.ceil(this.canvas.height * 0.04);
+		
+		let nameFontSize = Math.ceil(this.canvas.height * 0.028);
+		let underNameFontSize = Math.ceil(this.canvas.height * 0.018);
+		const nameMaxArea = Math.ceil(this.canvas.width * 0.24);
+		
+		const iconImageOffset = Math.ceil(this.canvas.height * 0.03);
+		const iconOpacity = 0.125;
+		
+		// Get primary text split into lines, no more than ``primaryTextMaxLines`` of them
+		
+		let primaryTextLines = null;
+		
+		do {
+			this.context.font = `${this.primaryFontStyle} ${primaryFontSize}px ${this.primaryFont}`;
+
+			primaryTextLines = splitStringIntoLines(
+				this.context,
+				this.primaryText,
+				this.canvas.width - primaryRectanglePaddingSides * 2,
+				primaryTextMaxLines,
+				true
+			).reverse();
+
+			if (primaryTextLines.length > primaryTextMaxLines) {
+				primaryFontSize -= 2;
+			}
+		} while (primaryTextLines.length > primaryTextMaxLines);
+
+		// Clear the canvas
+		this.context.clearRect(
+			0, 0,
+			this.canvas.width, this.canvas.height
+		);
+		
+		// Set image
+		if (this.primaryImage !== null) {
+			// https://github.com/DonkeyDushan/piratilol/blob/main/src/js/index.js
+			// Thanks to DonkeyDushan, the guy who made the joke 2021 campaign generator :D
+
+			const imageScaleX = this.canvas.width / this.primaryImage.width;
+			const imageScaleY = this.canvas.height / this.primaryImage.height;
+
+			const imageScale = Math.max(imageScaleX, imageScaleY) * this.primaryImageZoom;
+			
+			// https://stackoverflow.com/a/8529655
+			// Thanks to alex!
+			this.context.setTransform(
+				imageScale,
+				0, 0,
+				imageScale,
+				(this.canvas.width - this.primaryImage.width * imageScale) / 2 + this.primaryImageX * this.primaryImageZoom,
+				(this.canvas.height - this.primaryImage.height * imageScale) / 2 + this.primaryImageY * this.primaryImageZoom
+			);
+			this.context.drawImage(
+				this.primaryImage,
+				0, 0
+			);
+			this.context.setTransform(); // Reset transformation
+		}
+		
+		const firstPrimaryLine = primaryTextLines[primaryTextLines.length - 1].join(" ");
+		
+		// Create rectangle behind the primary text
+		const primaryRectangleHeight = (
+			primaryTextLines.length * (primaryFontSize + primaryFontLinePadding)
+			+ primaryRectanglePaddingTop
+			+ primaryRectanglePaddingBottom
+			+ primaryTextPaddingBottom
+			+ (
+				(
+					firstPrimaryLine.replace(/[a-zA-Z0-9À-ž]+/g, "").length
+					!== firstPrimaryLine.replace(/[a-zA-Z0-9]+/g, "").length
+				) ?
+				primaryRectangleAdditionalPaddingWithDiacritics :
+				0
+			)
+		);
+		
+		const classRef = this;
+		
+		// Create background gradient
+		const gradientLoadPromise = new Promise(
+			resolve => {
+				const gradientImage = new Image();
+				
+				gradientImage.onload = function() {
+					classRef.context.drawImage(
+						this,
+						0, 0,
+						classRef.canvas.width, classRef.canvas.height - primaryRectangleHeight
+					);
+					
+					resolve();
+				}
+				
+				gradientImage.src = "static/images/gradient.png";
+			}
+		);
+		
+		await gradientLoadPromise;
+		
+		if (this.secondaryText !== "") {
+			this.context.textAlign = "center";
+			this.context.font = `${secondaryFontSize}px ${this.primaryFont}`;
+			
+			while (
+				this.context.measureText(this.secondaryText).width
+				> (this.canvas.width - 2 * primaryRectanglePaddingSides)
+			) {
+				secondaryFontSize -= 2;
+				this.context.font = `${secondaryFontSize}px ${this.primaryFont}`;
+			}
+			
+			this.context.fillStyle = this.secondaryTextColor;
+			
+			this.context.fillText(
+				this.secondaryText,
+				this.canvas.width / 2, this.canvas.height - primaryRectangleHeight - secondaryTextPaddingBottom
+			);
+		}
+		
+		this.context.font = `${this.primaryFontStyle} ${primaryFontSize}px ${this.primaryFont}`;
+		
+		const foregroundRGB = hexToRgb(this.foregroundColor);
+		const foregroundLightness = (
+			0.2126 * foregroundRGB.r
+			+ 0.7152 * foregroundRGB.g
+			+ 0.0722 * foregroundRGB.b
+		)
+		
+		this.context.beginPath();
+		
+		const primaryRectangleStartingX = 0;
+		const primaryRectangleEndingX = this.canvas.width;
+		
+		this.context.fillStyle = this.foregroundColor;
+		
+		this.context.moveTo(
+			0,
+			this.canvas.height
+		);
+		this.context.lineTo(
+			this.canvas.width,
+			this.canvas.height
+		);
+		this.context.lineTo(
+			this.canvas.width,
+			this.canvas.height - primaryRectangleHeight - primaryRectangleAngle
+		);
+		this.context.lineTo(
+			0,
+			this.canvas.height - primaryRectangleHeight
+		);
+		
+		this.context.closePath();
+		
+		this.context.fill();
+		
+		function drawIconImage(image) {
+			const iconHeight = primaryRectangleHeight - 2 * iconImageOffset;
+			const iconWidth = (image.width * (iconHeight / image.height));
+			
+			classRef.context.globalAlpha = iconOpacity;
+			
+			const primaryTextRGB = hexToRgb(classRef.primaryTextColor);
+			
+			classRef.context.drawImage(
+				colorizeImage(
+					image,
+					iconWidth, iconHeight,
+					primaryTextRGB.r,
+					primaryTextRGB.g,
+					primaryTextRGB.b
+				),
+				iconImageOffset, classRef.canvas.height - iconImageOffset - iconHeight,
+				iconWidth, iconHeight
+			);
+			
+			classRef.context.globalAlpha = 1;
+		}
+		
+		// Create icon, if there is one
+		if (this.iconImage !== null) {
+			drawIconImage(this.iconImage);
+		} else if (this.iconSource !== null) {
+			const iconImageLoadPromise = new Promise(
+				resolve => {
+					const iconImage = new Image();
+					
+					iconImage.onload = function() {
+						drawIconImage(this);
+						
+						resolve();
+					}
+					
+					iconImage.src = this.iconSource;
+				}
+			);
+			
+			await iconImageLoadPromise;
+		}
+		
+		// Create primary text
+		this.context.textAlign = "left";
+		
+		const useLightHighlightAndUseDarkLogo = (foregroundLightness > 207);
+		
+		const primaryLineX = this.canvas.width / 2;
+		let currentPrimaryLineY = (
+			this.canvas.height
+			- primaryRectanglePaddingBottom
+			- primaryFontLinePadding
+			- primaryTextPaddingBottom
+		);
+		
+		let primaryTextHighlightedColor = null;
+		
+		const lowercasePrimaryTextHighlightColor = this.primaryTextHighlightColor.toLowerCase();
+		const hasColorOverride = (
+			lowercasePrimaryTextHighlightColor === "#209a37" ||
+			lowercasePrimaryTextHighlightColor === "#e63812"
+		);
+		
+		if (hasColorOverride) {
+			if (useLightHighlightAndUseDarkLogo) {
+				primaryTextHighlightedColor = this.foregroundColor;
+			} else {
+				primaryTextHighlightedColor = this.primaryTextColor;
+			}
+		} else if (!useLightHighlightAndUseDarkLogo) {
+			primaryTextHighlightedColor = this.foregroundColor;
+		} else {
+			primaryTextHighlightedColor = this.primaryTextColor;
+		}
+		
+		this.context.fillStyle = this.primaryTextColor;
+		
+		for (let line of primaryTextLines) {
+			let wordPosition = 0;
+			
+			for (let word of line) {
+				const previousWords = line.slice(0, wordPosition).join(" ");
+				const previousWordsWidth = this.context.measureText(
+					previousWords
+					+ (
+						(previousWords.length !== 0) ?
+						" " : ""
+					)
+				).width;
+				
+				const nextWords = line.slice(wordPosition + 1, line.length).join(" ")
+				const nextWordsWidth = this.context.measureText(
+					nextWords
+					+ (
+						(nextWords.length !== 0) ?
+						" " : ""
+					)
+				).width;
+				
+				let currentWordWidth = this.context.measureText(word).width;
+				
+				for (const word of line.slice(wordPosition + 1, line.length)) {
+					if (word.isHighlighted) {
+						currentWordWidth += this.context.measureText(word.toString() + " ").width;
+					} else {
+						break;
+					}
+				}
+				
+				if (word.isHighlighted) {
+					if (
+						wordPosition === 0 ||
+						!line[wordPosition - 1].isHighlighted
+					) {
+						this.context.fillStyle = this.primaryTextHighlightColor;
+						this.context.beginPath();
+						
+						const startingHighlightLineX = (
+							primaryLineX
+							+ Math.ceil(previousWordsWidth / 2)
+							- Math.ceil(nextWordsWidth / 2)
+							- Math.ceil(this.context.measureText(word).width / 2)
+						);
+						
+						this.context.moveTo(
+							startingHighlightLineX - highlightPaddingSides,
+							currentPrimaryLineY + highlightPaddingBottom
+						);
+						this.context.lineTo(
+							(
+								startingHighlightLineX
+								+ currentWordWidth
+								+ highlightPaddingSides
+							),
+							(
+								currentPrimaryLineY
+								+ highlightPaddingBottom
+								- Math.max(
+									(currentWordWidth * primaryRectangleAngle)
+									/ (this.canvas.width - 2 * primaryRectanglePaddingSides)
+								)
+							)
+						);
+						this.context.lineTo(
+							(
+								startingHighlightLineX
+								+ currentWordWidth
+								+ highlightPaddingSides
+							),
+							(
+								currentPrimaryLineY
+								- primaryFontSize
+								- highlightPaddingTop
+								- Math.max(
+									(currentWordWidth * primaryRectangleAngle)
+									/ (this.canvas.width - 2 * primaryRectanglePaddingSides)
+								)
+							)
+						);
+						this.context.lineTo(
+							startingHighlightLineX - highlightPaddingSides,
+							(
+								currentPrimaryLineY
+								- primaryFontSize
+								- highlightPaddingTop
+							)
+						);
+						
+						this.context.closePath();
+						
+						this.context.fill();
+					}
+					
+					this.context.fillStyle = primaryTextHighlightedColor;
+				}
+				
+				this.context.fillText(
+					word + " ",
+					(
+						primaryLineX
+						+ Math.ceil(previousWordsWidth / 2)
+						- Math.ceil(nextWordsWidth / 2)
+						- Math.ceil(this.context.measureText(word).width / 2)
+					),
+					currentPrimaryLineY
+				);
+				
+				wordPosition++;
+				
+				this.context.fillStyle = this.primaryTextColor;
+			}
+			
+			currentPrimaryLineY -= (primaryFontSize + primaryFontLinePadding);
+		}
+		
+		this.context.textAlign = "center";
+		
+		// Create name, if not empty
+		if (this.nameText !== "") {
+			// Create rectangle for name text
+			this.context.font = `bold ${nameFontSize}px 'Roboto Condensed'`;
+			
+			while (this.context.measureText(this.nameText).width > nameMaxArea) {
+				nameFontSize -= 2;
+				this.context.font = `bold ${nameFontSize}px 'Roboto Condensed'`;
+			}
+			
+			this.context.textAlign = "left";
+			
+			// Create name text itself
+			this.context.fillStyle = this.primaryTextColor;
+			this.context.fillText(
+				this.nameText,
+				logoTextOffsetSide, this.canvas.height - nameTextOffsetBottom
+			);
+			
+			if (this.underNameText !== "") {
+				this.context.font = `${underNameFontSize}px 'Roboto Condensed'`;
+				
+				while (this.context.measureText(this.underNameText).width > nameMaxArea) {
+					underNameFontSize -= 2;
+					this.context.font = `${underNameFontSize}px 'Roboto Condensed'`;
+				}
+				
+				this.context.fillText(
+					this.underNameText,
+					logoTextOffsetSide, this.canvas.height - nameTextOffsetBottom + nameFontSize
+				);
+			}
+		}
+
+		function drawLogoImage(image) {
+			const logoWidth = Math.ceil(image.width * (logoHeight / image.height));
+
+			classRef.context.drawImage(
+				image,
+				(
+					(!classRef.logoIsCenter) ?
+					classRef.canvas.width - logoWidth - logoTextOffsetSide :
+					(classRef.canvas.width - logoWidth) / 2
+				), classRef.canvas.height - logoHeight - logoBottomOffset,
+				logoWidth, logoHeight
+			);
+		}
+
+		if (this.logoImage === null) {
+			const logoImageLoadPromise = new Promise(
+				resolve => {
+					let logoImage = new Image();
+					
+					logoImage.onload = function() {
+						drawLogoImage(this);
+						
+						resolve();
+					}
+					
+					if (!useLightHighlightAndUseDarkLogo) {
+						logoImage.src = classRef.lightLogoDefaultSource;
+					} else {
+						logoImage.src = classRef.darkLogoDefaultSource;
+					}
+				}
+			);
+			
+			await logoImageLoadPromise;
+		} else {
+			drawLogoImage(this.logoImage);
+		}
+		
+		if (this.requesterText !== "") {
+			// https://newspaint.wordpress.com/2014/05/22/writing-rotated-text-on-a-javascript-canvas/
+			// Thanks to newspaint!
+			
+			this.context.save();
+
+			this.context.translate(this.canvas.width - 1, 0);
+
+			this.context.rotate(3 * Math.PI / 2);
+
+			let requesterFontSize = Math.ceil(this.canvas.width * 0.0175);
+			
+			do {
+				this.context.font = `${this.primaryFontStyle} ${requesterFontSize}px ${this.primaryFont}`;
+				
+				if (
+					this.context.measureText(this.requesterText).width
+					> primaryRectangleHeight - (this.canvas.height * 0.03)
+				) {
+					requesterFontSize -= 2;
+					this.context.font = `${this.primaryFontStyle} ${requesterFontSize}px ${this.primaryFont}`;
+				}
+			} while (
+				this.context.measureText(this.requesterText).width
+				> primaryRectangleHeight - (this.canvas.height * 0.03)
+			);
+			
+			this.context.fillStyle = this.requesterTextColor;
+
+			this.context.textAlign = "left";
+
+			this.context.globalAlpha = 0.6;
+			this.context.fillText(
+				this.requesterText,
+				-this.canvas.height * 0.985, -this.canvas.width * 0.99 + requesterFontSize
+			);
+			this.context.globalAlpha = 1;
+			
+			this.context.restore();
+		}
+		this.finalDrawHook();
+		this.stickerDrawHook();
+		
+		this.redrawing = false;
+	}
+	
+	// Text
+	async setSecondaryText(text, skipRedraw = false) {
+		this.secondaryText = text;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async setUnderNameText(text, skipRedraw = false) {
+		this.underNameText = text;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	// Icon
+	async setIconSource(url, skipRedraw = false) {
+		this.iconSource = url;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async setIconImageFromInput(imageInput, skipRedraw = false) {
+		if (imageInput.files.length == 0) {
+			return;
+		}
+		
+		const readPromise = new Promise(
+			resolve => {
+				const fileReader = new FileReader();
+				
+				let classRef = this;
+				
+				fileReader.onloadend = function(event) {
+					classRef.iconImage = new Image();
+					
+					classRef.iconImage.onload = function() {
+						if (!skipRedraw) {
+							classRef.redrawCanvas();
+						}
+						
+						resolve();
+					}
+					
+					classRef.iconImage.src = event.target.result;
+				}
+				
+				fileReader.readAsDataURL(imageInput.files[0]);
+			}
+		);
+		
+		await readPromise;
+	}
+	
+	async resetIconImage(skipRedraw = false) {
+		this.iconImage = null;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	// Color schemes
+	async setPrimaryColorScheme(scheme, skipRedraw = false) {
+		switch (scheme) {
+			case "black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "white-on-black":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor ="#000000";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "forum-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "forum-white-on-purple":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#962a51";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "zeleni-volary-bystrc-most-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "zeleni-volary-bystrc-most-white-on-green":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#00ad43";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "spolecne-s-piraty-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "spolecne-s-piraty-white-on-blue":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#21274e";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "louny-spolecne-black-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "louny-spolecne-white-on-purple":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#3e2a5b";
+				
+				this.setPrimaryTextHighlightColorScheme("gold", true);
+				
+				break;
+			case "litomerice-blue-on-white":
+				this.primaryTextColor = "#123172";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				
+				this.setPrimaryTextHighlightColorScheme("litomerice", true);
+				
+				break;
+			case "litomerice-white-on-blue":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#123172";
+				
+				this.setPrimaryTextHighlightColorScheme("litomerice", true);
+				
+				break;
+			case "stranane-gray-on-yellow":
+				this.primaryTextColor = "#4d4d4d";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				
+				break;
+			case "stranane-yellow-on-white":
+				this.primaryTextColor = "#4d4d4d";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				this.primaryTextHighlightColor = "#4d4d4d";
+				
+				break;
+			case "stranane-white-on-yellow":
+				this.primaryTextColor = "#4d4d4d";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#ffd500";
+				
+				break;
+			case "prusanky-black-on-yellow":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				
+				break;
+			case "prusanky-yellow-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffd500";
+				this.primaryTextHighlightColor = "#000000";
+				
+				break;
+			case "prusanky-white-on-yellow":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#ffd500";
+				
+				break;
+			case "ujezd-green-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#8ed4a3";
+				this.primaryTextHighlightColor = "#ffdd55";
+				
+				break;
+			case "ujezd-white-on-green":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#8ed4a3";
+				
+				break;
+			case "cssd-red-on-black":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#e63812";
+				
+				break;
+			case "cssd-black-on-red":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#000000";
+				
+				break;
+			case "jilemnice-purple-on-black":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#6e1646";
+				
+				break;
+			case "jilemnice-black-on-purple":
+				this.primaryTextColor = "#ffffff";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#000000";
+				
+				break;
+			case "novarole-white-on-green":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#ffffff";
+				this.primaryTextHighlightColor = "#a9ce2d";
+				
+				break;
+			case "novarole-green-on-white":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#a9ce2d";
+				
+				this.primaryTextHighlightColor = "#ffeda5";
+				
+				break;
+			case "novarole-green-on-black":
+				this.primaryTextColor = "#000000";
+				this.secondaryTextColor = "#ffffff";
+				this.foregroundColor = "#a9ce2d";
+				
+				this.primaryTextHighlightColor = "#ffeda5";
+				
+				break;
+			case "zeleni-melnik-yellow-name-rect":
+				await this.setPrimaryColorScheme("white-on-black", true);
+				
+				break;
+			default:
+				throw new Error("This scheme does not exist.");
+				break;
+		}
+		
+		this.requesterTextColor = this.primaryTextColor;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+
+	async setPrimaryTextHighlightColorScheme(scheme, skipRedraw = false) {
+		switch(scheme) {
+			case "gold":
+				this.primaryTextHighlightColor = "#ffeda5";
+				break;
+			case "litomerice":
+				this.primaryTextHighlightColor = "#afe87e";
+				break;
+			default:
+				throw new Error("This scheme does not exist.");
+				break;
+		}
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async setPrimaryTextHighlightColor(color, skipRedraw = false) {
+		this.primaryTextHighlightColor = color;
+		
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async setLogoIsCenter(isCenter, skipRedraw = false) {
+		this.logoIsCenter = isCenter;
+
+		if (!skipRedraw) {
+			await this.redrawCanvas();
+		}
+	}
+	
+	async loadData(
+		primaryImageInput = null,
+		primaryText = "",
+		nameText = "",
+		primaryColorScheme = "",
+		resultion = 2000,
+		skipRedraw = false
+	) {
+		await super.loadData(
+			primaryImageInput,
+			primaryText,
+			nameText,
+			primaryColorScheme,
+			resultion,
+			skipRedraw
+		);
+		
+		$("#icon-image-selection").val("Otevřená radnice 1");
+		$("#icon-image-selection").trigger("change");
+	}
+}
diff --git a/generator/static/js/ui.js b/generator/static/js/ui.js
index 7b898a5d3b086d5accd4f6703d5a555ddbacacf8..ca3e5506c06fd2633c57950639c85fcb1eec3451 100644
--- a/generator/static/js/ui.js
+++ b/generator/static/js/ui.js
@@ -43,6 +43,8 @@ const templateTypes = {
 	"eu-icons-image": EuIconsImage,
 	"nalodeni": Nalodeni,
 	"nalodeni-story": NalodeniStory,
+	"komise": Komise,
+	"komise-story": KomiseStory,
 	"rollup-big-logo-short-text": RollupBigLogoShortText,
 	"rollup-points": RollupPoints,
 	"rollup-short-and-long-text": RollupShortAndLongText,
diff --git a/generator/templates/generator.html b/generator/templates/generator.html
index e48ccbf5e57466864f8dc811d51aefcb16b60ad3..9336e97866240f4c32ea9ceadd328d0da2ba8665 100644
--- a/generator/templates/generator.html
+++ b/generator/templates/generator.html
@@ -200,10 +200,18 @@
 			type="text/javascript"
 			src="{{ url_for('static', filename='js/templates/nalodeni.js') }}"
 		></script>
+		<script
+			type="text/javascript"
+			src="{{ url_for('static', filename='js/templates/komise.js') }}"
+		></script>
 		<script
 			type="text/javascript"
 			src="{{ url_for('static', filename='js/templates/nalodeni-story.js') }}"
 		></script>
+		<script
+			type="text/javascript"
+			src="{{ url_for('static', filename='js/templates/komise-story.js') }}"
+		></script>
 		<script
 			type="text/javascript"
 			src="{{ url_for('static', filename='js/templates/rollup-big-logo-short-text.js') }}"
@@ -610,6 +618,15 @@
 								data-template-type="nalodeni-story"
 							>Nalodění - story</option>
 							
+							<option
+								data-image-source="static/images/examples/komise.png"
+								data-template-type="komise"
+							>Komise</option>
+							<option
+								data-image-source="static/images/examples/komise_story.png"
+								data-template-type="komise-story"
+							>Komise - story</option>
+							
 							<option
 								data-image-source="static/images/examples/rollup_big_logo_short_text.png"
 								data-template-type="rollup-big-logo-short-text"