pijou commited on
Commit
026c297
·
verified ·
1 Parent(s): f0ec517

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +729 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Emulator
3
- emoji: 🐠
4
- colorFrom: blue
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: emulator
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,729 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>RetroVault - Classic Gaming Hub</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/jsnes@1.0.0/dist/jsnes.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/gba.js@1.0.0/build/gba.min.js"></script>
11
+ <style>
12
+ @font-face {
13
+ font-family: 'Press Start 2P';
14
+ src: url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
15
+ }
16
+
17
+ body {
18
+ font-family: 'Press Start 2P', cursive;
19
+ background-color: #0f0f1a;
20
+ color: #e0e0ff;
21
+ overflow-x: hidden;
22
+ }
23
+
24
+ .neon-text {
25
+ text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #ff00de, 0 0 20px #ff00de;
26
+ }
27
+
28
+ .neon-box {
29
+ box-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6, 0 0 20px #0073e6;
30
+ }
31
+
32
+ .pixel-border {
33
+ border-image: repeating-linear-gradient(90deg, #ff00de, #ff00de 10px, #0073e6 10px, #0073e6 20px) 5;
34
+ border-width: 4px;
35
+ border-style: solid;
36
+ }
37
+
38
+ .tab-active {
39
+ background: linear-gradient(to bottom, #ff00de, #0073e6);
40
+ color: white;
41
+ transform: translateY(-5px);
42
+ }
43
+
44
+ .scanlines {
45
+ position: relative;
46
+ }
47
+
48
+ .scanlines:before {
49
+ content: "";
50
+ position: absolute;
51
+ top: 0;
52
+ left: 0;
53
+ width: 100%;
54
+ height: 100%;
55
+ background: linear-gradient(
56
+ to bottom,
57
+ transparent 50%,
58
+ rgba(0, 0, 0, 0.2) 51%
59
+ );
60
+ background-size: 100% 4px;
61
+ pointer-events: none;
62
+ z-index: 10;
63
+ }
64
+
65
+ .dark-mode {
66
+ background-color: #0f0f1a;
67
+ color: #e0e0ff;
68
+ }
69
+
70
+ .light-mode {
71
+ background-color: #f0f0ff;
72
+ color: #1a1a2e;
73
+ }
74
+
75
+ /* Pixel art buttons */
76
+ .btn-pixel {
77
+ position: relative;
78
+ display: inline-block;
79
+ padding: 10px 20px;
80
+ color: white;
81
+ background: #6a5acd;
82
+ text-decoration: none;
83
+ border-radius: 0;
84
+ border-bottom: 5px solid #483d8b;
85
+ transition: transform 0.1s, border-bottom 0.1s;
86
+ }
87
+
88
+ .btn-pixel:hover {
89
+ transform: translate(0, 2px);
90
+ border-bottom: 3px solid #483d8b;
91
+ }
92
+
93
+ .btn-pixel:active {
94
+ transform: translate(0, 5px);
95
+ border-bottom: 0px solid #483d8b;
96
+ }
97
+
98
+ /* CRT screen effect */
99
+ .crt-effect {
100
+ position: relative;
101
+ overflow: hidden;
102
+ }
103
+
104
+ .crt-effect:after {
105
+ content: " ";
106
+ display: block;
107
+ position: absolute;
108
+ top: 0;
109
+ left: 0;
110
+ bottom: 0;
111
+ right: 0;
112
+ background: rgba(18, 16, 16, 0.1);
113
+ opacity: 0.2;
114
+ z-index: 2;
115
+ pointer-events: none;
116
+ }
117
+
118
+ .crt-effect:before {
119
+ content: " ";
120
+ display: block;
121
+ position: absolute;
122
+ top: 0;
123
+ left: 0;
124
+ bottom: 0;
125
+ right: 0;
126
+ background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
127
+ z-index: 2;
128
+ background-size: 100% 2px, 3px 100%;
129
+ pointer-events: none;
130
+ }
131
+ </style>
132
+ </head>
133
+ <body class="dark-mode">
134
+ <div class="container mx-auto px-4 py-8">
135
+ <!-- Header -->
136
+ <header class="text-center mb-8">
137
+ <h1 class="text-5xl md:text-6xl font-bold mb-4 neon-text">RetroVault</h1>
138
+ <p class="text-xl md:text-2xl">Your classic gaming emporium</p>
139
+
140
+ <!-- Theme Toggle -->
141
+ <div class="flex justify-center mt-4">
142
+ <button id="themeToggle" class="btn-pixel px-6 py-2 rounded-full">
143
+ <i class="fas fa-moon"></i> Dark Mode
144
+ </button>
145
+ </div>
146
+ </header>
147
+
148
+ <!-- Main Dashboard -->
149
+ <div class="bg-gray-900 bg-opacity-70 rounded-lg p-6 neon-box">
150
+ <!-- Console Tabs -->
151
+ <div class="flex mb-6 border-b-2 border-purple-500">
152
+ <button id="nesTab" class="tab-active px-6 py-3 font-bold rounded-t-lg mr-2 transition-all">
153
+ <i class="fas fa-gamepad mr-2"></i> NES
154
+ </button>
155
+ <button id="gbaTab" class="px-6 py-3 font-bold rounded-t-lg mr-2 transition-all hover:bg-purple-900 hover:text-white">
156
+ <i class="fas fa-mobile-alt mr-2"></i> GBA
157
+ </button>
158
+ <button id="controlsTab" class="px-6 py-3 font-bold rounded-t-lg transition-all hover:bg-purple-900 hover:text-white">
159
+ <i class="fas fa-keyboard mr-2"></i> Controls
160
+ </button>
161
+ </div>
162
+
163
+ <!-- NES Section -->
164
+ <div id="nesSection" class="console-section">
165
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
166
+ <!-- Emulator Container -->
167
+ <div class="md:col-span-2">
168
+ <div class="bg-black p-4 rounded-lg crt-effect scanlines">
169
+ <div id="nesEmulator" class="mx-auto" style="width: 100%; height: 400px;"></div>
170
+ </div>
171
+
172
+ <div class="flex flex-wrap justify-center mt-4 gap-2">
173
+ <button id="nesLoad" class="btn-pixel">
174
+ <i class="fas fa-folder-open mr-2"></i> Load ROM
175
+ </button>
176
+ <button id="nesSaveState" class="btn-pixel">
177
+ <i class="fas fa-save mr-2"></i> Save State
178
+ </button>
179
+ <button id="nesLoadState" class="btn-pixel">
180
+ <i class="fas fa-file-upload mr-2"></i> Load State
181
+ </button>
182
+ <button id="nesFullscreen" class="btn-pixel">
183
+ <i class="fas fa-expand mr-2"></i> Fullscreen
184
+ </button>
185
+ <button id="nesReset" class="btn-pixel">
186
+ <i class="fas fa-redo mr-2"></i> Reset
187
+ </button>
188
+ </div>
189
+ </div>
190
+
191
+ <!-- Game Info -->
192
+ <div class="bg-gray-800 bg-opacity-70 rounded-lg p-4 pixel-border">
193
+ <h3 class="text-xl font-bold mb-4 text-center neon-text">Game Info</h3>
194
+ <div id="nesGameInfo" class="text-sm">
195
+ <p class="mb-2"><span class="text-purple-400">No game loaded</span></p>
196
+ <p class="mb-2">Controls:</p>
197
+ <ul class="list-disc pl-5">
198
+ <li>Arrow Keys: D-Pad</li>
199
+ <li>Z: A Button</li>
200
+ <li>X: B Button</li>
201
+ <li>Enter: Start</li>
202
+ <li>Shift: Select</li>
203
+ </ul>
204
+ <p class="mt-4 text-xs text-gray-400">Upload your own NES ROMs to play</p>
205
+ </div>
206
+ </div>
207
+ </div>
208
+ </div>
209
+
210
+ <!-- GBA Section (Hidden by default) -->
211
+ <div id="gbaSection" class="console-section hidden">
212
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
213
+ <!-- Emulator Container -->
214
+ <div class="md:col-span-2">
215
+ <div class="bg-black p-4 rounded-lg crt-effect scanlines">
216
+ <div id="gbaEmulator" class="mx-auto" style="width: 100%; height: 400px;"></div>
217
+ </div>
218
+
219
+ <div class="flex flex-wrap justify-center mt-4 gap-2">
220
+ <button id="gbaLoad" class="btn-pixel">
221
+ <i class="fas fa-folder-open mr-2"></i> Load ROM
222
+ </button>
223
+ <button id="gbaSaveState" class="btn-pixel">
224
+ <i class="fas fa-save mr-2"></i> Save State
225
+ </button>
226
+ <button id="gbaLoadState" class="btn-pixel">
227
+ <i class="fas fa-file-upload mr-2"></i> Load State
228
+ </button>
229
+ <button id="gbaFullscreen" class="btn-pixel">
230
+ <i class="fas fa-expand mr-2"></i> Fullscreen
231
+ </button>
232
+ <button id="gbaReset" class="btn-pixel">
233
+ <i class="fas fa-redo mr-2"></i> Reset
234
+ </button>
235
+ </div>
236
+ </div>
237
+
238
+ <!-- Game Info -->
239
+ <div class="bg-gray-800 bg-opacity-70 rounded-lg p-4 pixel-border">
240
+ <h3 class="text-xl font-bold mb-4 text-center neon-text">Game Info</h3>
241
+ <div id="gbaGameInfo" class="text-sm">
242
+ <p class="mb-2"><span class="text-purple-400">No game loaded</span></p>
243
+ <p class="mb-2">Controls:</p>
244
+ <ul class="list-disc pl-5">
245
+ <li>Arrow Keys: D-Pad</li>
246
+ <li>A: A Button</li>
247
+ <li>S: B Button</li>
248
+ <li>Enter: Start</li>
249
+ <li>Shift: Select</li>
250
+ <li>Q: L Button</li>
251
+ <li>W: R Button</li>
252
+ </ul>
253
+ <p class="mt-4 text-xs text-gray-400">Upload your own GBA ROMs to play</p>
254
+ </div>
255
+ </div>
256
+ </div>
257
+ </div>
258
+
259
+ <!-- Controls Section (Hidden by default) -->
260
+ <div id="controlsSection" class="console-section hidden">
261
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
262
+ <!-- Key Mapping -->
263
+ <div class="bg-gray-800 bg-opacity-70 rounded-lg p-4 pixel-border">
264
+ <h3 class="text-xl font-bold mb-4 text-center neon-text">Keyboard Controls</h3>
265
+ <div class="grid grid-cols-2 gap-4">
266
+ <div>
267
+ <h4 class="text-lg font-bold mb-2 text-purple-400">NES</h4>
268
+ <ul class="text-sm">
269
+ <li class="mb-1">Arrow Keys: D-Pad</li>
270
+ <li class="mb-1">Z: A Button</li>
271
+ <li class="mb-1">X: B Button</li>
272
+ <li class="mb-1">Enter: Start</li>
273
+ <li class="mb-1">Shift: Select</li>
274
+ </ul>
275
+ </div>
276
+ <div>
277
+ <h4 class="text-lg font-bold mb-2 text-purple-400">GBA</h4>
278
+ <ul class="text-sm">
279
+ <li class="mb-1">Arrow Keys: D-Pad</li>
280
+ <li class="mb-1">A: A Button</li>
281
+ <li class="mb-1">S: B Button</li>
282
+ <li class="mb-1">Enter: Start</li>
283
+ <li class="mb-1">Shift: Select</li>
284
+ <li class="mb-1">Q: L Button</li>
285
+ <li class="mb-1">W: R Button</li>
286
+ </ul>
287
+ </div>
288
+ </div>
289
+ </div>
290
+
291
+ <!-- Gamepad Info -->
292
+ <div class="bg-gray-800 bg-opacity-70 rounded-lg p-4 pixel-border">
293
+ <h3 class="text-xl font-bold mb-4 text-center neon-text">Gamepad Support</h3>
294
+ <div id="gamepadInfo" class="text-sm">
295
+ <p class="mb-4">Connect a gamepad and press any button to enable.</p>
296
+ <p class="mb-2">Supported gamepads:</p>
297
+ <ul class="list-disc pl-5">
298
+ <li class="mb-1">Xbox 360/One</li>
299
+ <li class="mb-1">PlayStation 3/4</li>
300
+ <li class="mb-1">Generic USB gamepads</li>
301
+ </ul>
302
+ <p class="mt-4 text-xs text-gray-400">Buttons will map automatically to standard layout</p>
303
+ </div>
304
+ </div>
305
+ </div>
306
+
307
+ <div class="mt-6 bg-gray-800 bg-opacity-70 rounded-lg p-4 pixel-border">
308
+ <h3 class="text-xl font-bold mb-4 text-center neon-text">Customize Controls</h3>
309
+ <div class="text-center">
310
+ <button id="remapControls" class="btn-pixel px-6 py-2">
311
+ <i class="fas fa-keyboard mr-2"></i> Remap Keys
312
+ </button>
313
+ <p class="mt-2 text-xs text-gray-400">Coming soon: Custom key mapping for keyboard and gamepad</p>
314
+ </div>
315
+ </div>
316
+ </div>
317
+ </div>
318
+
319
+ <!-- Footer -->
320
+ <footer class="mt-8 text-center text-sm text-gray-500">
321
+ <p>RetroVault - Play classic games in your browser</p>
322
+ <p class="mt-1">Note: You must provide your own legally obtained ROM files</p>
323
+ </footer>
324
+ </div>
325
+
326
+ <!-- Hidden file inputs -->
327
+ <input type="file" id="nesFileInput" accept=".nes" class="hidden">
328
+ <input type="file" id="gbaFileInput" accept=".gba" class="hidden">
329
+
330
+ <script>
331
+ // Theme Toggle
332
+ const themeToggle = document.getElementById('themeToggle');
333
+ const body = document.body;
334
+
335
+ themeToggle.addEventListener('click', () => {
336
+ if (body.classList.contains('dark-mode')) {
337
+ body.classList.remove('dark-mode');
338
+ body.classList.add('light-mode');
339
+ themeToggle.innerHTML = '<i class="fas fa-sun mr-2"></i> Light Mode';
340
+ } else {
341
+ body.classList.remove('light-mode');
342
+ body.classList.add('dark-mode');
343
+ themeToggle.innerHTML = '<i class="fas fa-moon mr-2"></i> Dark Mode';
344
+ }
345
+ });
346
+
347
+ // Tab Switching
348
+ const nesTab = document.getElementById('nesTab');
349
+ const gbaTab = document.getElementById('gbaTab');
350
+ const controlsTab = document.getElementById('controlsTab');
351
+
352
+ const nesSection = document.getElementById('nesSection');
353
+ const gbaSection = document.getElementById('gbaSection');
354
+ const controlsSection = document.getElementById('controlsSection');
355
+
356
+ function resetTabs() {
357
+ nesTab.classList.remove('tab-active');
358
+ gbaTab.classList.remove('tab-active');
359
+ controlsTab.classList.remove('tab-active');
360
+
361
+ nesTab.classList.add('hover:bg-purple-900', 'hover:text-white');
362
+ gbaTab.classList.add('hover:bg-purple-900', 'hover:text-white');
363
+ controlsTab.classList.add('hover:bg-purple-900', 'hover:text-white');
364
+
365
+ nesSection.classList.add('hidden');
366
+ gbaSection.classList.add('hidden');
367
+ controlsSection.classList.add('hidden');
368
+ }
369
+
370
+ nesTab.addEventListener('click', () => {
371
+ resetTabs();
372
+ nesTab.classList.add('tab-active');
373
+ nesTab.classList.remove('hover:bg-purple-900', 'hover:text-white');
374
+ nesSection.classList.remove('hidden');
375
+ });
376
+
377
+ gbaTab.addEventListener('click', () => {
378
+ resetTabs();
379
+ gbaTab.classList.add('tab-active');
380
+ gbaTab.classList.remove('hover:bg-purple-900', 'hover:text-white');
381
+ gbaSection.classList.remove('hidden');
382
+ });
383
+
384
+ controlsTab.addEventListener('click', () => {
385
+ resetTabs();
386
+ controlsTab.classList.add('tab-active');
387
+ controlsTab.classList.remove('hover:bg-purple-900', 'hover:text-white');
388
+ controlsSection.classList.remove('hidden');
389
+ });
390
+
391
+ // NES Emulator
392
+ const nes = new jsnes.NES({
393
+ onFrame: function(frameBuffer) {
394
+ const canvas = document.createElement('canvas');
395
+ canvas.width = 256;
396
+ canvas.height = 240;
397
+ const context = canvas.getContext('2d');
398
+ const imageData = context.createImageData(canvas.width, canvas.height);
399
+
400
+ for (let i = 0; i < frameBuffer.length; i++) {
401
+ imageData.data[i * 4] = frameBuffer[i] >> 16 & 0xFF;
402
+ imageData.data[i * 4 + 1] = frameBuffer[i] >> 8 & 0xFF;
403
+ imageData.data[i * 4 + 2] = frameBuffer[i] & 0xFF;
404
+ imageData.data[i * 4 + 3] = 0xFF;
405
+ }
406
+
407
+ context.putImageData(imageData, 0, 0);
408
+ document.getElementById('nesEmulator').innerHTML = '';
409
+ document.getElementById('nesEmulator').appendChild(canvas);
410
+ },
411
+ onAudioSample: function(left, right) {
412
+ // Audio handling would go here
413
+ }
414
+ });
415
+
416
+ // NES Controls
417
+ document.addEventListener('keydown', (e) => {
418
+ if (!nesSection.classList.contains('hidden')) {
419
+ switch(e.keyCode) {
420
+ case 38: nes.buttonDown(1, jsnes.Controller.BUTTON_UP); break; // Up
421
+ case 40: nes.buttonDown(1, jsnes.Controller.BUTTON_DOWN); break; // Down
422
+ case 37: nes.buttonDown(1, jsnes.Controller.BUTTON_LEFT); break; // Left
423
+ case 39: nes.buttonDown(1, jsnes.Controller.BUTTON_RIGHT); break; // Right
424
+ case 90: nes.buttonDown(1, jsnes.Controller.BUTTON_A); break; // Z (A)
425
+ case 88: nes.buttonDown(1, jsnes.Controller.BUTTON_B); break; // X (B)
426
+ case 13: nes.buttonDown(1, jsnes.Controller.BUTTON_START); break; // Enter (Start)
427
+ case 16: nes.buttonDown(1, jsnes.Controller.BUTTON_SELECT); break; // Shift (Select)
428
+ }
429
+ }
430
+ });
431
+
432
+ document.addEventListener('keyup', (e) => {
433
+ if (!nesSection.classList.contains('hidden')) {
434
+ switch(e.keyCode) {
435
+ case 38: nes.buttonUp(1, jsnes.Controller.BUTTON_UP); break;
436
+ case 40: nes.buttonUp(1, jsnes.Controller.BUTTON_DOWN); break;
437
+ case 37: nes.buttonUp(1, jsnes.Controller.BUTTON_LEFT); break;
438
+ case 39: nes.buttonUp(1, jsnes.Controller.BUTTON_RIGHT); break;
439
+ case 90: nes.buttonUp(1, jsnes.Controller.BUTTON_A); break;
440
+ case 88: nes.buttonUp(1, jsnes.Controller.BUTTON_B); break;
441
+ case 13: nes.buttonUp(1, jsnes.Controller.BUTTON_START); break;
442
+ case 16: nes.buttonUp(1, jsnes.Controller.BUTTON_SELECT); break;
443
+ }
444
+ }
445
+ });
446
+
447
+ // NES File Handling
448
+ const nesFileInput = document.getElementById('nesFileInput');
449
+ const nesLoadBtn = document.getElementById('nesLoad');
450
+
451
+ nesLoadBtn.addEventListener('click', () => {
452
+ nesFileInput.click();
453
+ });
454
+
455
+ nesFileInput.addEventListener('change', (e) => {
456
+ const file = e.target.files[0];
457
+ if (!file) return;
458
+
459
+ const reader = new FileReader();
460
+ reader.onload = (e) => {
461
+ const rom = new Uint8Array(e.target.result);
462
+ nes.loadROM(rom);
463
+
464
+ // Update game info
465
+ document.getElementById('nesGameInfo').innerHTML = `
466
+ <p class="mb-2"><span class="text-purple-400">${file.name}</span></p>
467
+ <p class="mb-2">Controls:</p>
468
+ <ul class="list-disc pl-5">
469
+ <li>Arrow Keys: D-Pad</li>
470
+ <li>Z: A Button</li>
471
+ <li>X: B Button</li>
472
+ <li>Enter: Start</li>
473
+ <li>Shift: Select</li>
474
+ </ul>
475
+ <p class="mt-4 text-xs text-gray-400">Press Save State to save your progress</p>
476
+ `;
477
+ };
478
+ reader.readAsArrayBuffer(file);
479
+ });
480
+
481
+ // NES Save/Load State
482
+ let nesState = null;
483
+
484
+ document.getElementById('nesSaveState').addEventListener('click', () => {
485
+ nesState = nes.toJSON();
486
+ alert('Game state saved!');
487
+ });
488
+
489
+ document.getElementById('nesLoadState').addEventListener('click', () => {
490
+ if (nesState) {
491
+ nes.fromJSON(nesState);
492
+ alert('Game state loaded!');
493
+ } else {
494
+ alert('No saved state found!');
495
+ }
496
+ });
497
+
498
+ // NES Fullscreen
499
+ document.getElementById('nesFullscreen').addEventListener('click', () => {
500
+ const emulator = document.getElementById('nesEmulator');
501
+ if (emulator.requestFullscreen) {
502
+ emulator.requestFullscreen();
503
+ } else if (emulator.webkitRequestFullscreen) {
504
+ emulator.webkitRequestFullscreen();
505
+ } else if (emulator.msRequestFullscreen) {
506
+ emulator.msRequestFullscreen();
507
+ }
508
+ });
509
+
510
+ // NES Reset
511
+ document.getElementById('nesReset').addEventListener('click', () => {
512
+ nes.reset();
513
+ });
514
+
515
+ // GBA Emulator
516
+ let gba = null;
517
+ let gbaRom = null;
518
+
519
+ // GBA File Handling
520
+ const gbaFileInput = document.getElementById('gbaFileInput');
521
+ const gbaLoadBtn = document.getElementById('gbaLoad');
522
+
523
+ gbaLoadBtn.addEventListener('click', () => {
524
+ gbaFileInput.click();
525
+ });
526
+
527
+ gbaFileInput.addEventListener('change', (e) => {
528
+ const file = e.target.files[0];
529
+ if (!file) return;
530
+
531
+ const reader = new FileReader();
532
+ reader.onload = (e) => {
533
+ const rom = new Uint8Array(e.target.result);
534
+ gbaRom = rom;
535
+
536
+ // Initialize GBA emulator
537
+ if (!gba) {
538
+ gba = new GameBoyAdvance();
539
+
540
+ // Set up video
541
+ const canvas = document.createElement('canvas');
542
+ canvas.width = 240;
543
+ canvas.height = 160;
544
+ const context = canvas.getContext('2d');
545
+ document.getElementById('gbaEmulator').innerHTML = '';
546
+ document.getElementById('gbaEmulator').appendChild(canvas);
547
+
548
+ gba.setCanvas(canvas);
549
+
550
+ // Set up audio (would need Web Audio API implementation)
551
+ // gba.setAudioDevice(...);
552
+
553
+ // Start emulation
554
+ gba.setInterval(() => {
555
+ gba.runStable();
556
+ }, 0);
557
+ }
558
+
559
+ // Load ROM
560
+ gba.loadRom(rom);
561
+
562
+ // Update game info
563
+ document.getElementById('gbaGameInfo').innerHTML = `
564
+ <p class="mb-2"><span class="text-purple-400">${file.name}</span></p>
565
+ <p class="mb-2">Controls:</p>
566
+ <ul class="list-disc pl-5">
567
+ <li>Arrow Keys: D-Pad</li>
568
+ <li>A: A Button</li>
569
+ <li>S: B Button</li>
570
+ <li>Enter: Start</li>
571
+ <li>Shift: Select</li>
572
+ <li>Q: L Button</li>
573
+ <li>W: R Button</li>
574
+ </ul>
575
+ <p class="mt-4 text-xs text-gray-400">Press Save State to save your progress</p>
576
+ `;
577
+ };
578
+ reader.readAsArrayBuffer(file);
579
+ });
580
+
581
+ // GBA Controls
582
+ document.addEventListener('keydown', (e) => {
583
+ if (!gba || gbaSection.classList.contains('hidden')) return;
584
+
585
+ // Map keys to GBA buttons
586
+ // This would need to be implemented based on GBA.js's input handling
587
+ // The following is a placeholder implementation
588
+ switch(e.keyCode) {
589
+ case 38: /* Up */ break;
590
+ case 40: /* Down */ break;
591
+ case 37: /* Left */ break;
592
+ case 39: /* Right */ break;
593
+ case 65: /* A (A Button) */ break;
594
+ case 83: /* S (B Button) */ break;
595
+ case 13: /* Enter (Start) */ break;
596
+ case 16: /* Shift (Select) */ break;
597
+ case 81: /* Q (L Button) */ break;
598
+ case 87: /* W (R Button) */ break;
599
+ }
600
+ });
601
+
602
+ // GBA Save/Load State
603
+ let gbaState = null;
604
+
605
+ document.getElementById('gbaSaveState').addEventListener('click', () => {
606
+ if (!gba) {
607
+ alert('No game loaded!');
608
+ return;
609
+ }
610
+
611
+ // This would need proper implementation with GBA.js
612
+ // gbaState = gba.saveState();
613
+ alert('Game state saved! (Placeholder - would save state in real implementation)');
614
+ });
615
+
616
+ document.getElementById('gbaLoadState').addEventListener('click', () => {
617
+ if (!gbaState) {
618
+ alert('No saved state found!');
619
+ return;
620
+ }
621
+
622
+ // This would need proper implementation with GBA.js
623
+ // gba.loadState(gbaState);
624
+ alert('Game state loaded! (Placeholder - would load state in real implementation)');
625
+ });
626
+
627
+ // GBA Fullscreen
628
+ document.getElementById('gbaFullscreen').addEventListener('click', () => {
629
+ const emulator = document.getElementById('gbaEmulator');
630
+ if (emulator.requestFullscreen) {
631
+ emulator.requestFullscreen();
632
+ } else if (emulator.webkitRequestFullscreen) {
633
+ emulator.webkitRequestFullscreen();
634
+ } else if (emulator.msRequestFullscreen) {
635
+ emulator.msRequestFullscreen();
636
+ }
637
+ });
638
+
639
+ // GBA Reset
640
+ document.getElementById('gbaReset').addEventListener('click', () => {
641
+ if (!gba || !gbaRom) {
642
+ alert('No game loaded!');
643
+ return;
644
+ }
645
+
646
+ gba.loadRom(gbaRom);
647
+ });
648
+
649
+ // Gamepad Support
650
+ window.addEventListener("gamepadconnected", (e) => {
651
+ document.getElementById('gamepadInfo').innerHTML = `
652
+ <p class="mb-2"><span class="text-green-400">Gamepad connected:</span> ${e.gamepad.id}</p>
653
+ <p class="mb-2">Standard mapping:</p>
654
+ <ul class="list-disc pl-5">
655
+ <li>D-Pad: D-Pad</li>
656
+ <li>A Button: A</li>
657
+ <li>B Button: B</li>
658
+ <li>Start: Start</li>
659
+ <li>Select: Select</li>
660
+ <li>Shoulder Buttons: L/R</li>
661
+ </ul>
662
+ <p class="mt-4 text-xs text-gray-400">Press buttons to control the game</p>
663
+ `;
664
+
665
+ // Start polling gamepad state
666
+ if (!gamepadPolling) {
667
+ gamepadPolling = true;
668
+ pollGamepads();
669
+ }
670
+ });
671
+
672
+ window.addEventListener("gamepaddisconnected", (e) => {
673
+ document.getElementById('gamepadInfo').innerHTML = `
674
+ <p class="mb-4">Connect a gamepad and press any button to enable.</p>
675
+ <p class="mb-2">Supported gamepads:</p>
676
+ <ul class="list-disc pl-5">
677
+ <li class="mb-1">Xbox 360/One</li>
678
+ <li class="mb-1">PlayStation 3/4</li>
679
+ <li class="mb-1">Generic USB gamepads</li>
680
+ </ul>
681
+ <p class="mt-4 text-xs text-gray-400">Buttons will map automatically to standard layout</p>
682
+ `;
683
+ });
684
+
685
+ let gamepadPolling = false;
686
+ let prevGamepadState = {};
687
+
688
+ function pollGamepads() {
689
+ if (!gamepadPolling) return;
690
+
691
+ const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
692
+
693
+ for (let i = 0; i < gamepads.length; i++) {
694
+ const gamepad = gamepads[i];
695
+ if (!gamepad) continue;
696
+
697
+ // Handle gamepad input
698
+ // This would need to be implemented based on the emulator's input handling
699
+ // The following is a placeholder implementation
700
+
701
+ // Example: Check if A button (usually index 0) is pressed
702
+ if (gamepad.buttons[0] && gamepad.buttons[0].pressed) {
703
+ // Handle A button press
704
+ }
705
+
706
+ // Example: Check D-pad or analog stick
707
+ if (gamepad.axes[1] < -0.5) {
708
+ // Up pressed
709
+ } else if (gamepad.axes[1] > 0.5) {
710
+ // Down pressed
711
+ }
712
+
713
+ if (gamepad.axes[0] < -0.5) {
714
+ // Left pressed
715
+ } else if (gamepad.axes[0] > 0.5) {
716
+ // Right pressed
717
+ }
718
+ }
719
+
720
+ requestAnimationFrame(pollGamepads);
721
+ }
722
+
723
+ // Remap Controls Button
724
+ document.getElementById('remapControls').addEventListener('click', () => {
725
+ alert('Key remapping feature coming soon!');
726
+ });
727
+ </script>
728
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=pijou/emulator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
729
+ </html>