diff --git a/v4/assets/game.html b/v4/assets/game.html
new file mode 100644
index 00000000..921b64ae
--- /dev/null
+++ b/v4/assets/game.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+ Loading... | 3kh0
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
diff --git a/v4/assets/game.js b/v4/assets/game.js
new file mode 100644
index 00000000..9f21fc80
--- /dev/null
+++ b/v4/assets/game.js
@@ -0,0 +1,91 @@
+(function () {
+ const { search, pathname } = window.location;
+ const urlParams = new URLSearchParams(search);
+ const gameSubpath = urlParams.get("game");
+ const origin = localStorage.getItem("instance");
+ const cdn = localStorage.getItem("cdn");
+ const instance = origin.replace(location.origin, "");
+
+ if (!origin || !cdn) {
+ window.location.href = `../?onload=window.location.href='${pathname}${search}'`;
+ }
+
+ if (gameSubpath && origin) {
+ fetch("./json/games.json")
+ .then((res) => res.json())
+ .then((games) => {
+ const game = games.find((g) => g.root === gameSubpath);
+ if (game) {
+ const { name, root, img, file } = game;
+ document.title = `Play ${name} | 3kh0`;
+ window.history.pushState({}, "", `${origin}games/${gameSubpath}`);
+ document.querySelector("#game").textContent = name;
+ document.querySelector(".loader").innerHTML = `
`;
+ document.querySelector("#startgame").classList.remove("hidden");
+
+ const startGameHandler = (e) => {
+ document.body.innerHTML = `
+
+
+ `;
+ };
+
+ document.querySelector("#startgame").addEventListener("click", startGameHandler);
+ } else {
+ console.error(`The game "${gameSubpath}" was not found.`);
+ }
+ })
+ .catch((e) => {
+ console.error(e);
+ });
+ } else {
+ console.error("Could not load game");
+ if (!origin) {
+ console.error("The origin of the instance could not be found");
+ }
+ if (!gameSubpath) {
+ console.error("The game was not provided");
+ }
+ }
+
+ if (window.top === window.self) {
+ window.location.href = document.referrer || "../";
+ }
+
+ function getColorValues(hexcolor) {
+ const r = parseInt(hexcolor.substr(1, 2), 16);
+ const g = parseInt(hexcolor.substr(3, 2), 16);
+ const b = parseInt(hexcolor.substr(5, 2), 16);
+ const yiq = (r * 299 + g * 587 + b * 114) / 1000;
+ return {
+ contrast: yiq >= 128 ? "#1c1c1c" : "white",
+ text: yiq >= 128 ? "white" : "black"
+ };
+ }
+
+ const theme = localStorage.getItem("theme");
+
+ if (!theme) {
+ document.body.setAttribute("theme", "default");
+ } else if (theme !== "custom") {
+ document.body.setAttribute("theme", theme);
+ } else if (theme === "custom") {
+ const customTheme = localStorage.getItem("theme_color");
+ document.body.setAttribute("theme", "custom");
+ const { contrast, text } = getColorValues(customTheme);
+ document.body.style = `--theme: ${customTheme}; --background: ${contrast}; --text: ${text}; --text-secondary: ${text};`;
+
+ if (location.pathname.includes("/settings")) {
+ document.querySelector("#theme_color").value = customTheme;
+ }
+ }
+ })();
+
\ No newline at end of file
diff --git a/v4/assets/globe.svg b/v4/assets/globe.svg
new file mode 100644
index 00000000..373255bf
--- /dev/null
+++ b/v4/assets/globe.svg
@@ -0,0 +1 @@
+
\ No newline at end of file