diff --git a/public/emulator.css b/public/emulator.css
new file mode 100644
index 0000000..bf67f3f
--- /dev/null
+++ b/public/emulator.css
@@ -0,0 +1,19 @@
+body,html {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ overflow: hidden;
+ background: transparent;
+}
+
+.game {
+ width: 100%;
+ height: 100%;
+ max-width: 100%;
+ display: block;
+ margin: 0 auto;
+}
+
+.ejs_menu_bar {
+ display: none !important;
+}
\ No newline at end of file
diff --git a/public/emulator.html b/public/emulator.html
index 221b75e..0f1ff00 100644
--- a/public/emulator.html
+++ b/public/emulator.html
@@ -2,184 +2,14 @@
- Test
-
-
+ Emulator Window
+
-
-
+
\ No newline at end of file
diff --git a/public/emulator.js b/public/emulator.js
new file mode 100644
index 0000000..12338a5
--- /dev/null
+++ b/public/emulator.js
@@ -0,0 +1,175 @@
+// Init EJS stuff
+class HomeplayEmulator {
+ scriptElement = null;
+ initInterval = null;
+ oldGetRetroArchCfg = null;
+
+ constructor() {
+ // Set up the EJS stuff
+ window.EJS_player = "#game";
+ window.EJS_pathtodata = "https://cdn.emulatorjs.org/stable/data/";
+ window.EJS_language = "en-US";
+ window.EJS_volume = 0;
+ window.EJS_startOnLoaded = true;
+ window.EJS_backgroundColor = '#000';
+
+ window.EJS_Buttons = {
+ playPause: false,
+ restart: false,
+ mute: false,
+ settings: false,
+ fullscreen: false,
+ saveState: false,
+ loadState: false,
+ screenRecord: false,
+ gamepad: false,
+ cheat: false,
+ volume: false,
+ saveSavFiles: false,
+ loadSavFiles: false,
+ quickSave: false,
+ quickLoad: false,
+ screenshot: false,
+ cacheManager: false,
+ exitEmulation: false
+ }
+
+ window.EJS_defaultOptions = {
+
+ };
+
+ // Bind events
+ window.EJS_ready = this.onEJSReady;
+ window.EJS_onGameStart = this.onEJSGameStart;
+ window.EJS_onGameEnd = this.onEJSGameEnd;
+ window.EJS_onSaveState = this.onEJSSaveState;
+ window.EJS_onLoadState = this.onEJSLoadState;
+ window.onmessage = this.onMessage;
+
+ // Begin the init interval
+ this.initInterval = setInterval(() => {
+ this.send({ message: 'iframe_loaded' });
+ }, 1000);
+ }
+
+ send = data => {
+ window.parent.postMessage(data, '*');
+ }
+
+ init = data => {
+ window.EJS_gameUrl = `/api/v1/rom?id=${data.gameId}`;
+ window.EJS_core = data.core;
+ window.EJS_gameName = data.gameName;
+ window.EJS_externalFiles = {
+ '/homeplay/saves/': `/api/v1/save?id=${data.gameId}`
+ }
+
+ this.scriptElement = document.createElement('script');
+ this.scriptElement.src = 'https://cdn.emulatorjs.org/stable/data/loader.js';
+ document.body.appendChild(this.scriptElement);
+
+ clearInterval(this.initInterval);
+ }
+
+ onEJSReady = () => {
+ // Modify the EJS stuff
+ this.oldGetRetroArchCfg = window.EJS_GameManager.prototype.getRetroArchCfg;
+ const raConfig = (...a) => this.getRetroArchCfg(...a);
+ window.EJS_GameManager.prototype.getRetroArchCfg = function() {
+ return raConfig(this);
+ }
+
+ this.send({ message: 'ready' });
+
+ console.log('EJS Ready');
+ }
+
+ onEJSGameStart = () => {
+ console.log('EJS Game Start');
+ }
+
+ onEJSGameEnd = () => {
+ console.log('EJS Game End');
+ }
+
+ onEJSSaveState = () => {
+ console.log('EJS Save State');
+ }
+
+ onEJSLoadState = () => {
+ console.log('EJS Load State');;
+ }
+
+ onMessage = e => {
+ const { data } = e;
+
+ if(!data) {
+ console.error('No data');
+ return;
+ }
+
+ const { message } = data;
+ switch(message) {
+ case 'init':
+ this.init(data);
+ break;
+
+ case 'volume':
+ window.EJS_volume = data.volume;
+ break;
+
+ case 'save':
+ window.EJS_emulator.saveSaveFiles();
+ break;
+
+ default:
+ console.error('Unknown message', message);
+ }
+ }
+
+ md5File = async path => {
+ const buffer = window.EJS_emulator.gameManager.FS.readFile(path);
+ const hash = await crypto.subtle.digest('SHA-256', buffer);
+ const hashArray = Array.from(new Uint8Array(hash));
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
+ return hashHex;
+ }
+
+ getRetroArchCfg = (gameManager) => {
+ const ejsConfig = this.oldGetRetroArchCfg.call(gameManager);
+
+ // Parse back into key value pair
+ const raConfig = ejsConfig.split('\n').reduce((acc, line) => {
+ if(!line.length) return acc;
+ const [key, value] = line.split('=');
+ acc[key.trim()] = value.trim();
+ return acc;
+ }, {});
+
+ // Add new options
+ raConfig['savefiles_in_content_dir'] = false;
+ raConfig['sort_savefiles_by_content_enable'] = false;
+ raConfig['sort_savefiles_enable'] = false;
+ raConfig['savefile_directory'] = '/homeplay/saves';
+
+ // Return back as RA config string
+ return Object.entries(raConfig).map(([k, v]) => `${k} = ${v}`).join('\n');
+ }
+}
+
+// const emulatorSave = async () => {
+// // First, we get the currently saved MD5 hash of all files in the save
+// // directory
+// const contents = EJS_emulator.gameManager.FS.readdir('/homeplay/saves').filter(f => !f.startsWith('.'));
+// const hashes = await Promise.all(contents.map(f => md5File(`/homeplay/saves/${f}`)));
+// EJS_emulator.gameManager.saveSaveFiles();
+// const newHashes = await Promise.all(contents.map(f => md5File(`/homeplay/saves/${f}`)));
+// const changedFiles = contents.filter((f, i) => hashes[i] !== newHashes[i]);
+// console.log('Changed files', changedFiles);
+
+// send({
+// message: ''
+// })
+// }
+
+window.homeplay = new HomeplayEmulator();
\ No newline at end of file
diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx
index 795e129..6518309 100644
--- a/src/pages/_document.tsx
+++ b/src/pages/_document.tsx
@@ -1,4 +1,3 @@
-import { LanguageProvider } from '@/providers/LanguageProvider';
import { Html, Head, Main, NextScript, DocumentProps } from 'next/document';
const RootDocument:React.FC = props => {