diff --git a/assets/fastforward.svg b/assets/fastforward.svg
new file mode 100644
index 0000000000000000000000000000000000000000..52439673412bb731dbb2b61f1542a7d303d447d4
--- /dev/null
+++ b/assets/fastforward.svg
@@ -0,0 +1,8 @@
+<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+    <style type="text/css" id="current-color-scheme">
+        .ColorScheme-Text {
+            color:#eff0f1;
+        }
+    </style>
+    <path d="m8 2v12l7-6zm-7 0v12l7-6z" class="ColorScheme-Text" fill="currentColor"/>
+</svg>
diff --git a/assets/logo.svg b/assets/logo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b14083d82504258fccf9f66766fff63694b10e53
--- /dev/null
+++ b/assets/logo.svg
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="299.99982"
+   height="300.00003"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docbase="C:\Eigene Dateien\Video AG"
+   sodipodi:docname="logo.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0"
+   inkscape:export-filename="Q:\video AG\fs-pub-video\folien\logo-1024.png"
+   inkscape:export-xdpi="307.20001"
+   inkscape:export-ydpi="307.20001">
+  <defs
+     id="defs4">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective21" />
+    <linearGradient
+       id="linearGradient2041">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.00000000"
+         id="stop2043" />
+      <stop
+         style="stop-color:#7d7d7d;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2045" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2041"
+       id="linearGradient2047"
+       x1="194.17578"
+       y1="139.59265"
+       x2="250.03906"
+       y2="139.59265"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(317,-57)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4889823"
+     inkscape:cx="71.681092"
+     inkscape:cy="217.8489"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="1400"
+     inkscape:window-height="988"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     showgrid="false"
+     inkscape:snap-bbox="false"
+     inkscape:snap-nodes="true"
+     inkscape:object-paths="false"
+     inkscape:object-nodes="true"
+     objecttolerance="10"
+     gridtolerance="10000"
+     guidetolerance="10000"
+     showborder="true"
+     inkscape:showpageshadow="true"
+     borderlayer="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Ebene 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-438.99979,0.6379836)">
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#ffffff;fill-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path2393"
+       sodipodi:cx="454"
+       sodipodi:cy="112.36218"
+       sodipodi:rx="87"
+       sodipodi:ry="56"
+       d="M 541,112.36218 A 87,56 0 1 1 367,112.36218 A 87,56 0 1 1 541,112.36218 z"
+       transform="matrix(-1.977323e-3,-1.724137,2.678569,-3.071905e-3,288.9275,932.4654)"
+       inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
+       inkscape:export-xdpi="90.000000"
+       inkscape:export-ydpi="90.000000" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path1306"
+       sodipodi:cx="281.42856"
+       sodipodi:cy="270.93362"
+       sodipodi:rx="38.57143"
+       sodipodi:ry="44.285713"
+       d="M 319.99999,270.93362 A 38.57143,44.285713 0 1 1 242.85713,270.93362 A 38.57143,44.285713 0 1 1 319.99999,270.93362 z"
+       transform="matrix(0.972222,0,0,0.846774,264.7456,-151.7001)"
+       inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
+       inkscape:export-xdpi="90.000000"
+       inkscape:export-ydpi="90.000000" />
+    <text
+       xml:space="preserve"
+       style="font-size:72px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:url(#linearGradient2047);fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
+       x="511"
+       y="108.36218"
+       id="text1308"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
+       inkscape:export-xdpi="90.000000"
+       inkscape:export-ydpi="90.000000"><tspan
+         sodipodi:role="line"
+         id="tspan1312"
+         x="511"
+         y="108.36218"
+         style="fill:url(#linearGradient2047);fill-opacity:1">V</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
+       id="path3517"
+       sodipodi:cx="454"
+       sodipodi:cy="112.36218"
+       sodipodi:rx="87"
+       sodipodi:ry="56"
+       d="M 541,112.36218 A 87,56 0 1 1 454,56.362183 L 454,112.36218 z"
+       transform="matrix(-1.977323e-3,-1.724137,2.678569,-3.071905e-3,288.9275,932.4654)"
+       sodipodi:start="0"
+       sodipodi:end="4.712389"
+       inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
+       inkscape:export-xdpi="90.000000"
+       inkscape:export-ydpi="90.000000" />
+    <text
+       xml:space="preserve"
+       style="font-size:28px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
+       x="598"
+       y="105.36218"
+       id="text2055"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
+       inkscape:export-xdpi="90.000000"
+       inkscape:export-ydpi="90.000000"><tspan
+         sodipodi:role="line"
+         id="tspan2785"
+         x="598"
+         y="105.36218"
+         style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Arial Black">ideo</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
+       x="511"
+       y="243.36218"
+       id="text2051"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
+       inkscape:export-xdpi="90.000000"
+       inkscape:export-ydpi="90.000000"><tspan
+         sodipodi:role="line"
+         id="tspan2053"
+         x="511"
+         y="243.36218"
+         style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;font-family:Arial Black">AG</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:72px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0.25098039;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
+       x="471"
+       y="108.36218"
+       id="text4979"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
+       inkscape:export-xdpi="90.000000"
+       inkscape:export-ydpi="90.000000"><tspan
+         sodipodi:role="line"
+         id="tspan4981"
+         x="471"
+         y="108.36218">V</tspan></text>
+  </g>
+</svg>
diff --git a/src/render/ffmpeg.rs b/src/render/ffmpeg.rs
index 1c94319c22c9cda4ced32af48574cebb9bd5d9a4..70e5dbaf58c5d5d82cae77c209d7d781e32c5e5e 100644
--- a/src/render/ffmpeg.rs
+++ b/src/render/ffmpeg.rs
@@ -2,9 +2,10 @@ use super::cmd;
 use crate::time::{format_time, Time};
 use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
 use rational::Rational;
-use std::process::Command;
+use std::{borrow::Cow, process::Command};
 
 pub(crate) struct FfmpegInput {
+	pub(crate) concat: bool,
 	pub(crate) loop_input: bool,
 	pub(crate) fps: Option<Rational>,
 	pub(crate) start: Option<Time>,
@@ -15,6 +16,7 @@ pub(crate) struct FfmpegInput {
 impl FfmpegInput {
 	pub(crate) fn new(path: PathBuf) -> Self {
 		Self {
+			concat: false,
 			loop_input: false,
 			fps: None,
 			start: None,
@@ -24,6 +26,9 @@ impl FfmpegInput {
 	}
 
 	fn append_to_cmd(self, cmd: &mut Command) {
+		if self.concat {
+			cmd.arg("-f").arg("concat").arg("-safe").arg("0");
+		}
 		if self.loop_input {
 			cmd.arg("-loop").arg("1");
 		}
@@ -40,8 +45,65 @@ impl FfmpegInput {
 	}
 }
 
+pub(crate) enum Filter {
+	Concat {
+		inputs: Vec<Cow<'static, str>>,
+		n: usize,
+		output: Cow<'static, str>
+	},
+
+	FadeIn {
+		input: Cow<'static, str>,
+		start: Time,
+		duration: Time,
+		output: Cow<'static, str>
+	},
+
+	FadeOut {
+		input: Cow<'static, str>,
+		start: Time,
+		duration: Time,
+		output: Cow<'static, str>
+	},
+
+	Overlay {
+		video_input: Cow<'static, str>,
+		overlay_input: Cow<'static, str>,
+		x: Cow<'static, str>,
+		y: Cow<'static, str>,
+		output: Cow<'static, str>
+	},
+
+	GenerateSilence {
+		output: Cow<'static, str>
+	}
+}
+
+impl Filter {
+	fn is_video_filter(&self) -> bool {
+		matches!(
+			self,
+			Self::Concat { .. }
+				| Self::FadeIn { .. }
+				| Self::FadeOut { .. }
+				| Self::Overlay { .. }
+		)
+	}
+
+	fn is_audio_filter(&self) -> bool {
+		matches!(
+			self,
+			Self::Concat { .. }
+				| Self::FadeIn { .. }
+				| Self::FadeOut { .. }
+				| Self::GenerateSilence { .. }
+		)
+	}
+}
+
 pub(crate) struct Ffmpeg {
 	inputs: Vec<FfmpegInput>,
+	filters: Vec<Filter>,
 	output: PathBuf
 }
 
@@ -49,6 +111,7 @@ impl Ffmpeg {
 	pub fn new(output: PathBuf) -> Self {
 		Self {
 			inputs: Vec::new(),
+			filters: Vec::new(),
 			output
 		}
 	}
@@ -57,9 +120,13 @@ impl Ffmpeg {
 		let mut cmd = cmd();
 		cmd.arg("ffmpeg").arg("-hide_banner");
 
+		// determine whether the video need to be re-encoded
+		let venc = self.filters.iter().any(|f| f.is_video_filter());
+		let aenc = self.filters.iter().any(|f| f.is_audio_filter());
+
 		// initialise a vaapi device if one exists
 		let vaapi_device: PathBuf = "/dev/dri/renderD128".into();
-		let vaapi = vaapi_device.exists();
+		let vaapi = venc && vaapi_device.exists();
 		if vaapi {
 			cmd.arg("-vaapi_device").arg(&vaapi_device);
 		}
@@ -72,6 +139,20 @@ impl Ffmpeg {
 		// always try to synchronise audio
 		cmd.arg("-async").arg("1");
 
+		// TODO apply filters
+
+		// append encoding options
+		if vaapi {
+			cmd.arg("-c:v").arg("h264_vaapi");
+			cmd.arg("-rc_mode").arg("CQP");
+			cmd.arg("-global_quality").arg("22");
+		} else if venc {
+			cmd.arg("-c:v").arg("libx264");
+			cmd.arg("-crf").arg("22");
+		} else {
+			cmd.arg("-c:v").arg("copy");
+		}
+
 		unimplemented!()
 	}
 }
diff --git a/src/render/mod.rs b/src/render/mod.rs
index 28126a54962a99df7ee48b454034adc42bad0e63..843d910207d51eb77cc118e09e0247ae538b4f90 100644
--- a/src/render/mod.rs
+++ b/src/render/mod.rs
@@ -4,6 +4,7 @@ pub mod ffmpeg;
 
 use crate::{
 	iotro::intro,
+	render::ffmpeg::Ffmpeg,
 	time::{format_date, Time},
 	Project, ProjectSourceMetadata, Resolution
 };
@@ -133,6 +134,20 @@ impl<'a> Renderer<'a> {
 	pub(crate) fn preprocess(&self, project: &mut Project) -> anyhow::Result<()> {
 		assert!(!project.progress.preprocessed);
 
+		let logo = self.target.join("logo.svg");
+		fs::write(
+			&logo,
+			include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/logo.svg"))
+		)?;
+		let fastforward = self.target.join("fastforward.svg");
+		fs::write(
+			&fastforward,
+			include_bytes!(concat!(
+				env!("CARGO_MANIFEST_DIR"),
+				"/assets/fastforward.svg"
+			))
+		)?;
+
 		let recording_txt = self.target.join("recording.txt");
 		let mut file = File::create(recording_txt)?;
 		for filename in &project.source.files {
@@ -141,7 +156,8 @@ impl<'a> Renderer<'a> {
 		drop(file);
 
 		println!("\x1B[1m ==> Concatenating Video and Normalising Audio ...");
-		let mut ffmpeg = Ffmpeg::new();
+		let recording_mp4 = self.target.join("recording.mp4");
+		let mut ffmpeg = Ffmpeg::new(recording_mp4);
 
 		// project.source.metadata = Some(ProjectSourceMetadata {
 		// 	source_duration: ffprobe_video("format=duration", input)?.parse()?