diff --git a/client/SkribblContainer.js b/client/SkribblContainer.js
new file mode 100644
index 0000000000000000000000000000000000000000..4675aafa9ecef69a676029a0e7926aac0e3148c4
--- /dev/null
+++ b/client/SkribblContainer.js
@@ -0,0 +1,24 @@
+/**
+ * Custom element `<skribbl-container>` that functions as a root element for the game, containing and managing both the game and all its menus, taking care of high-level state managment.
+ */
+export default class SkribblContainer extends HTMLElement {
+	constructor(){
+		super();
+		this.attachShadow({mode:"open"});
+		this.shadowRoot.innerHTML = `
+			<style>
+				:host {
+					display: block;
+					position: fixed;
+					top: 0;
+					right: 0;
+					bottom: 0;
+					left: 0;
+					--background-color: #efefefef;
+					background-image: linear-gradient(var(--background-color),var(--background-color)), url(./res/background.png);
+				}
+			</style>
+		`;
+	}
+}
+customElements.define("skribbl-container",SkribblContainer);
\ No newline at end of file
diff --git a/client/res/.gitignore b/client/res/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c5d9347ecac15b7ea248e668896fbfdc0e2f8dca
--- /dev/null
+++ b/client/res/.gitignore
@@ -0,0 +1 @@
+*.kra~
\ No newline at end of file
diff --git a/client/res/background.kra b/client/res/background.kra
new file mode 100644
index 0000000000000000000000000000000000000000..0a370a6b7c99ea88ed5d1d3dee47e4e970bc25a1
Binary files /dev/null and b/client/res/background.kra differ
diff --git a/client/res/background.png b/client/res/background.png
new file mode 100644
index 0000000000000000000000000000000000000000..3d1df01224e04c7466f66d766b0ca323f503111f
Binary files /dev/null and b/client/res/background.png differ
diff --git a/client/script.js b/client/script.js
index 7dfb1ddd05c64ee96f92bfe92ddee825fab68a1e..968bfdeec6beeecc22b843bfc2d8a50fc5ac66fd 100644
--- a/client/script.js
+++ b/client/script.js
@@ -1,4 +1,5 @@
 import Signaler from "./Signaler.js";
+import SkribblContainer from "./SkribblContainer.js";
 
 document.addEventListener("DOMContentLoaded",async()=>{
 	if (document.location.hash){
@@ -16,24 +17,28 @@ document.addEventListener("DOMContentLoaded",async()=>{
 	}else{
 		/** @type {HTMLButtonElement} *///@ts-ignore
 		const button = document.getElementById("button");
-		button.addEventListener("click",async e=>{
+		await new Promise(resolve=>{button.addEventListener("click",async e=>{
 			button.disabled = true;
-			let id = await Signaler.host(async({connection,dataChannel})=>{
-				console.group("New connection!");
-				console.log("connection:",connection);
-				console.log("dataChannel:",dataChannel);
-				console.groupEnd();
-				dataChannel.onmessage = (e)=>{
-					console.log("Message through DataChannel:",e.data);
-				}
-				if (dataChannel.readyState!="open"){
-					await new Promise(resolve=>{
-						dataChannel.onopen = resolve;
-					});
-				}
-				dataChannel.send("Oh hello there :3");
-			});
-			alert(document.location.host+document.location.pathname+"#"+id);
+			resolve();
+		})});
+		let id = await Signaler.host(async({connection,dataChannel})=>{
+			console.group("New connection!");
+			console.log("connection:",connection);
+			console.log("dataChannel:",dataChannel);
+			console.groupEnd();
+			dataChannel.onmessage = (e)=>{
+				console.log("Message through DataChannel:",e.data);
+			}
+			if (dataChannel.readyState!="open"){
+				await new Promise(resolve=>{
+					dataChannel.onopen = resolve;
+				});
+			}
+			dataChannel.send("Oh hello there :3");
 		});
+		alert(document.location.host+document.location.pathname+"#"+id);
 	}
+	const game = new SkribblContainer();
+	document.body.innerHTML = "";
+	document.body.appendChild(game);
 });
\ No newline at end of file