nova64 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +25 -8
  2. package/bin/nova64.js +165 -0
  3. package/dist/assets/console-CY_kygm3.js +14 -0
  4. package/dist/assets/console-CY_kygm3.js.map +1 -0
  5. package/dist/assets/main-l0sNRNKZ.js.map +1 -0
  6. package/dist/assets/sky/studio/nx.png +0 -0
  7. package/dist/assets/sky/studio/ny.png +0 -0
  8. package/dist/assets/sky/studio/nz.png +0 -0
  9. package/dist/assets/sky/studio/px.png +0 -0
  10. package/dist/assets/sky/studio/py.png +0 -0
  11. package/dist/assets/sky/studio/pz.png +0 -0
  12. package/dist/assets/vanilla-Dcuy32gi.js +2 -0
  13. package/dist/assets/vanilla-Dcuy32gi.js.map +1 -0
  14. package/dist/console.html +899 -0
  15. package/dist/docs/BENCHMARK.md +77 -0
  16. package/dist/docs/CHEATSHEET.md +255 -0
  17. package/dist/docs/EFFECTS_API_GUIDE.md +577 -0
  18. package/dist/docs/EFFECTS_QUICK_REFERENCE.md +331 -0
  19. package/dist/docs/FONT_CHARACTER_REFERENCE.md +219 -0
  20. package/dist/docs/FREE_GLB_ASSETS.md +330 -0
  21. package/dist/docs/FULLSCREEN_BUTTON_FEATURE.md +296 -0
  22. package/dist/docs/GAMEPAD_SUPPORT.md +348 -0
  23. package/dist/docs/GAME_IMPROVEMENTS.md +278 -0
  24. package/dist/docs/GAME_QUALITY_STATUS.md +300 -0
  25. package/dist/docs/MIGRATION_GUIDE.md +553 -0
  26. package/dist/docs/NOVA64_3D_API.md +356 -0
  27. package/dist/docs/NOVA64_API_REFERENCE.md +1406 -0
  28. package/dist/docs/NOVA64_UI_API.md +503 -0
  29. package/dist/docs/UI_SYSTEM_SUMMARY.md +445 -0
  30. package/dist/docs/VOXEL_ENGINE_GUIDE.md +662 -0
  31. package/dist/docs/VOXEL_QUICK_REFERENCE.md +386 -0
  32. package/dist/docs/api-3d.html +750 -0
  33. package/dist/docs/api-effects.html +385 -0
  34. package/dist/docs/api-improvements.md +121 -0
  35. package/dist/docs/api-skybox.html +407 -0
  36. package/dist/docs/api-sprites.html +321 -0
  37. package/dist/docs/api-voxel.html +337 -0
  38. package/dist/docs/api.html +543 -0
  39. package/dist/docs/assets.html +306 -0
  40. package/dist/docs/audio.html +340 -0
  41. package/dist/docs/blogs.html +286 -0
  42. package/dist/docs/collision.html +316 -0
  43. package/dist/docs/console.html +247 -0
  44. package/dist/docs/editor.html +297 -0
  45. package/dist/docs/font.html +247 -0
  46. package/dist/docs/framebuffer.html +247 -0
  47. package/dist/docs/fullscreen-button.html +297 -0
  48. package/dist/docs/gpu-systems.html +247 -0
  49. package/dist/docs/index.html +580 -0
  50. package/dist/docs/input.html +491 -0
  51. package/dist/docs/physics.html +311 -0
  52. package/dist/docs/screens.html +311 -0
  53. package/dist/docs/storage.html +311 -0
  54. package/dist/docs/textinput.html +332 -0
  55. package/dist/docs/ui.html +488 -0
  56. package/dist/examples/3d-advanced/code.js +695 -0
  57. package/dist/examples/adventure-comic-3d/code.js +342 -0
  58. package/dist/examples/audio-lab/code.js +150 -0
  59. package/dist/examples/boids-flocking/code.js +270 -0
  60. package/dist/examples/crystal-cathedral-3d/code.js +706 -0
  61. package/dist/examples/cyberpunk-city-3d/code.js +1383 -0
  62. package/dist/examples/demoscene/README.md +192 -0
  63. package/dist/examples/demoscene/code.js +1081 -0
  64. package/dist/examples/demoscene/meta.json +21 -0
  65. package/dist/examples/dungeon-crawler-3d/code.js +1117 -0
  66. package/dist/examples/f-zero-nova-3d/code.js +865 -0
  67. package/dist/examples/f-zero-nova-3d/code_old.js +1555 -0
  68. package/dist/examples/fps-demo-3d/code.js +744 -0
  69. package/dist/examples/game-of-life-3d/code.js +338 -0
  70. package/dist/examples/generative-art/code.js +632 -0
  71. package/dist/examples/hello-3d/code.js +325 -0
  72. package/dist/examples/hello-skybox/code.js +183 -0
  73. package/dist/examples/hello-world/code.js +19 -0
  74. package/dist/examples/input-showcase/code.js +109 -0
  75. package/dist/examples/instancing-demo/code.js +315 -0
  76. package/dist/examples/minecraft-demo/code.js +387 -0
  77. package/dist/examples/model-viewer-3d/code.js +114 -0
  78. package/dist/examples/mystical-realm-3d/code.js +1203 -0
  79. package/dist/examples/nature-explorer-3d/code.js +1318 -0
  80. package/dist/examples/particles-demo/code.js +522 -0
  81. package/dist/examples/pbr-showcase/code.js +140 -0
  82. package/dist/examples/physics-demo-3d/code.js +948 -0
  83. package/dist/examples/screen-demo/code.js +267 -0
  84. package/dist/examples/shooter-demo-3d/code.js +1286 -0
  85. package/dist/examples/space-combat-3d/IMPLEMENTATION_SUMMARY.md +109 -0
  86. package/dist/examples/space-combat-3d/README.md +135 -0
  87. package/dist/examples/space-combat-3d/code.js +1332 -0
  88. package/dist/examples/space-harrier-3d/code.js +923 -0
  89. package/dist/examples/star-fox-nova-3d/code.js +1116 -0
  90. package/dist/examples/star-fox-nova-3d/code_backup.js +410 -0
  91. package/dist/examples/star-fox-nova-3d/code_broken.js +1821 -0
  92. package/dist/examples/storage-quest/code.js +209 -0
  93. package/dist/examples/strider-demo-3d/IMPROVEMENT_OPTIONS.md +285 -0
  94. package/dist/examples/strider-demo-3d/cache-test.html +132 -0
  95. package/dist/examples/strider-demo-3d/code-fixed.js +582 -0
  96. package/dist/examples/strider-demo-3d/code-old.js +1537 -0
  97. package/dist/examples/strider-demo-3d/code.js +1462 -0
  98. package/dist/examples/strider-demo-3d/code.js.bak2 +1169 -0
  99. package/dist/examples/strider-demo-3d/fix-game.sh +53 -0
  100. package/dist/examples/super-plumber-64/README.md +128 -0
  101. package/dist/examples/super-plumber-64/code.js +1185 -0
  102. package/dist/examples/super-plumber-64/index.html +88 -0
  103. package/dist/examples/test-2d-overlay/code.js +32 -0
  104. package/dist/examples/test-font/code.js +51 -0
  105. package/dist/examples/test-minimal/code.js +21 -0
  106. package/dist/examples/ui-demo/code.js +306 -0
  107. package/dist/examples/wing-commander-space/README.md +180 -0
  108. package/dist/examples/wing-commander-space/code.js +1285 -0
  109. package/dist/examples/wizardry-3d/CHANGELOG.md +366 -0
  110. package/dist/examples/wizardry-3d/code.js +3928 -0
  111. package/dist/index.html +666 -0
  112. package/dist/os9-shell/assets/index-DIHfrTaW.css +1 -0
  113. package/dist/os9-shell/assets/index-KchE_ngx.js +483 -0
  114. package/dist/os9-shell/assets/index-KchE_ngx.js.map +1 -0
  115. package/dist/os9-shell/index.html +23 -0
  116. package/dist/os9-shell/nova-icon.svg +12 -0
  117. package/index.html +6 -1
  118. package/package.json +37 -32
  119. package/public/assets/sky/studio/nx.png +0 -0
  120. package/public/assets/sky/studio/ny.png +0 -0
  121. package/public/assets/sky/studio/nz.png +0 -0
  122. package/public/assets/sky/studio/px.png +0 -0
  123. package/public/assets/sky/studio/py.png +0 -0
  124. package/public/assets/sky/studio/pz.png +0 -0
  125. package/public/os9-shell/assets/index-KchE_ngx.js +483 -0
  126. package/public/os9-shell/assets/index-KchE_ngx.js.map +1 -0
  127. package/public/os9-shell/index.html +10 -1
  128. package/runtime/api-2d.js +301 -21
  129. package/runtime/api-3d/pbr.js +45 -1
  130. package/runtime/api-3d.js +1 -0
  131. package/runtime/api-effects.js +90 -3
  132. package/runtime/api-gameutils.js +476 -0
  133. package/runtime/api-generative.js +610 -0
  134. package/runtime/api-skybox.js +54 -0
  135. package/runtime/api-voxel.js +139 -28
  136. package/runtime/gpu-threejs.js +13 -9
  137. package/runtime/ui.js +2 -2
  138. package/src/main.js +20 -0
  139. package/public/os9-shell/assets/index-B1Uvacma.js +0 -32825
  140. package/public/os9-shell/assets/index-B1Uvacma.js.map +0 -1
@@ -0,0 +1,899 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>NOVA-64 Console</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet" />
8
+ <link
9
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap"
10
+ rel="stylesheet"
11
+ />
12
+ <style>
13
+ :root {
14
+ --bg: #090a0f;
15
+ --panel: rgba(21, 24, 34, 0.85);
16
+ --text: #e2e8f0;
17
+ --muted: #94a3b8;
18
+ --accent: #0ea5e9;
19
+ --accent-hover: #38bdf8;
20
+ --neon: #f43f5e;
21
+ --border: rgba(255, 255, 255, 0.1);
22
+ --glass: rgba(255, 255, 255, 0.05);
23
+ }
24
+ html,
25
+ body {
26
+ background: var(--bg);
27
+ margin: 0;
28
+ min-height: 100vh;
29
+ color: var(--text);
30
+ font-family: 'Inter', sans-serif;
31
+ overflow-x: hidden;
32
+ overflow-y: auto;
33
+ background-image:
34
+ radial-gradient(circle at 50% 0%, rgba(14, 165, 233, 0.1) 0%, transparent 50%),
35
+ radial-gradient(circle at 100% 100%, rgba(244, 63, 94, 0.05) 0%, transparent 50%);
36
+ }
37
+
38
+ .shell {
39
+ display: grid;
40
+ grid-template-columns: 1fr 340px;
41
+ gap: 0;
42
+ min-height: 100vh;
43
+ box-sizing: border-box;
44
+ }
45
+
46
+ .stage {
47
+ display: flex;
48
+ flex-direction: column;
49
+ align-items: center;
50
+ justify-content: center;
51
+ padding: 20px;
52
+ position: relative;
53
+ background: radial-gradient(circle, #1a1e29 0%, #090a0f 100%);
54
+ }
55
+
56
+ /* CRT Hardware Wrapper */
57
+ .hardware-bezel {
58
+ background: linear-gradient(145deg, #2a2a2a, #0a0a0a);
59
+ padding: 30px 30px 50px 30px;
60
+ border-radius: 20px;
61
+ box-shadow:
62
+ 0 0 0 2px #444,
63
+ 0 25px 50px -12px rgba(0, 0, 0, 0.8),
64
+ inset 0 4px 6px rgba(255, 255, 255, 0.1),
65
+ inset 0 -4px 6px rgba(0, 0, 0, 0.8);
66
+ position: relative;
67
+ }
68
+
69
+ .hardware-brand {
70
+ position: absolute;
71
+ bottom: 12px;
72
+ left: 50%;
73
+ transform: translateX(-50%);
74
+ font-family: 'VT323', monospace;
75
+ color: #888;
76
+ font-size: 28px;
77
+ letter-spacing: 6px;
78
+ text-shadow:
79
+ 0 -1px 0 rgba(0, 0, 0, 0.9),
80
+ 0 1px 0 rgba(255, 255, 255, 0.2);
81
+ font-weight: bold;
82
+ }
83
+
84
+ .screen-container {
85
+ position: relative;
86
+ border-radius: 8px;
87
+ overflow: hidden;
88
+ border: 4px solid #050505;
89
+ box-shadow:
90
+ inset 0 0 40px rgba(0, 0, 0, 0.9),
91
+ 0 0 10px rgba(14, 165, 233, 0.4);
92
+ background: #000;
93
+ /* Simulate TV curve slightly */
94
+ border-radius: 2% / 3%;
95
+ }
96
+
97
+ canvas {
98
+ image-rendering: auto;
99
+ width: 1280px;
100
+ height: 720px;
101
+ background: #000;
102
+ display: block;
103
+ max-width: 100%;
104
+ height: auto;
105
+ }
106
+
107
+ /* CRT Scanline Overlay */
108
+ .scanlines {
109
+ position: absolute;
110
+ top: 0;
111
+ left: 0;
112
+ right: 0;
113
+ bottom: 0;
114
+ background:
115
+ linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.15) 50%),
116
+ linear-gradient(
117
+ 90deg,
118
+ rgba(255, 0, 0, 0.03),
119
+ rgba(0, 255, 0, 0.01),
120
+ rgba(0, 0, 255, 0.03)
121
+ );
122
+ background-size:
123
+ 100% 4px,
124
+ 3px 100%;
125
+ pointer-events: none;
126
+ z-index: 10;
127
+ opacity: 0.8;
128
+ }
129
+
130
+ .screen-glare {
131
+ position: absolute;
132
+ top: 0;
133
+ left: 0;
134
+ right: 0;
135
+ bottom: 0;
136
+ background: radial-gradient(
137
+ 120% 120% at 30% 10%,
138
+ rgba(255, 255, 255, 0.08) 0%,
139
+ transparent 50%
140
+ );
141
+ pointer-events: none;
142
+ z-index: 11;
143
+ mix-blend-mode: screen;
144
+ }
145
+
146
+ .panel {
147
+ background: var(--panel);
148
+ backdrop-filter: blur(24px);
149
+ -webkit-backdrop-filter: blur(24px);
150
+ border-left: 1px solid var(--border);
151
+ padding: 30px 24px;
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 20px;
155
+ box-shadow: -10px 0 30px rgba(0, 0, 0, 0.6);
156
+ overflow-y: auto;
157
+ z-index: 20;
158
+ }
159
+
160
+ .row {
161
+ display: flex;
162
+ gap: 12px;
163
+ align-items: center;
164
+ flex-wrap: wrap;
165
+ }
166
+
167
+ .col {
168
+ display: flex;
169
+ flex-direction: column;
170
+ gap: 8px;
171
+ width: 100%;
172
+ }
173
+
174
+ label {
175
+ font-size: 11px;
176
+ text-transform: uppercase;
177
+ letter-spacing: 1px;
178
+ font-weight: 700;
179
+ color: var(--muted);
180
+ }
181
+
182
+ select,
183
+ button {
184
+ background: var(--glass);
185
+ color: var(--text);
186
+ border: 1px solid var(--border);
187
+ border-radius: 8px;
188
+ padding: 10px 14px;
189
+ font-size: 13px;
190
+ font-family: 'Inter', sans-serif;
191
+ transition: all 0.2s ease;
192
+ }
193
+
194
+ select {
195
+ width: 100%;
196
+ cursor: pointer;
197
+ appearance: none;
198
+ background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
199
+ background-repeat: no-repeat;
200
+ background-position: right 12px center;
201
+ background-size: 16px;
202
+ padding-right: 40px;
203
+ }
204
+
205
+ select:hover,
206
+ select:focus {
207
+ border-color: var(--accent);
208
+ outline: none;
209
+ background-color: rgba(255, 255, 255, 0.1);
210
+ }
211
+
212
+ select option {
213
+ background: #1e2532;
214
+ color: #fff;
215
+ }
216
+
217
+ button {
218
+ cursor: pointer;
219
+ font-weight: 600;
220
+ display: flex;
221
+ align-items: center;
222
+ justify-content: center;
223
+ gap: 8px;
224
+ }
225
+
226
+ button:hover {
227
+ background: rgba(255, 255, 255, 0.1);
228
+ transform: translateY(-1px);
229
+ }
230
+
231
+ button:active {
232
+ transform: translateY(1px);
233
+ }
234
+
235
+ .btn-primary {
236
+ background: rgba(14, 165, 233, 0.15);
237
+ color: var(--accent);
238
+ border: 1px solid rgba(14, 165, 233, 0.3);
239
+ }
240
+ .btn-primary:hover {
241
+ background: rgba(14, 165, 233, 0.25);
242
+ border-color: var(--accent);
243
+ }
244
+
245
+ .btn-magic {
246
+ background: linear-gradient(
247
+ 135deg,
248
+ rgba(139, 92, 246, 0.2) 0%,
249
+ rgba(217, 70, 239, 0.2) 100%
250
+ );
251
+ border: 1px solid rgba(217, 70, 239, 0.4);
252
+ color: #f0abfc;
253
+ }
254
+
255
+ .btn-magic:hover {
256
+ background: linear-gradient(
257
+ 135deg,
258
+ rgba(139, 92, 246, 0.3) 0%,
259
+ rgba(217, 70, 239, 0.3) 100%
260
+ );
261
+ border-color: rgba(217, 70, 239, 0.6);
262
+ box-shadow: 0 4px 15px rgba(217, 70, 239, 0.2);
263
+ }
264
+
265
+ .hr {
266
+ height: 1px;
267
+ background: var(--border);
268
+ margin: 4px 0;
269
+ }
270
+
271
+ .stat-box {
272
+ background: #000;
273
+ border-radius: 8px;
274
+ padding: 12px;
275
+ border: 1px solid #333;
276
+ font-family: 'VT323', monospace;
277
+ font-size: 18px;
278
+ color: #10b981;
279
+ letter-spacing: 1px;
280
+ text-shadow: 0 0 5px rgba(16, 185, 129, 0.5);
281
+ text-align: center;
282
+ box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.8);
283
+ }
284
+
285
+ .title {
286
+ font-family: 'Inter', sans-serif;
287
+ font-weight: 800;
288
+ font-size: 24px;
289
+ color: #fff;
290
+ margin-bottom: 4px;
291
+ letter-spacing: -0.5px;
292
+ background: linear-gradient(135deg, #0ea5e9, #a855f7);
293
+ -webkit-background-clip: text;
294
+ -webkit-text-fill-color: transparent;
295
+ }
296
+
297
+ .subtitle {
298
+ font-size: 12px;
299
+ color: var(--muted);
300
+ line-height: 1.4;
301
+ }
302
+
303
+ .footer {
304
+ font-size: 12px;
305
+ color: var(--muted);
306
+ margin-top: auto;
307
+ padding-top: 20px;
308
+ text-align: center;
309
+ }
310
+
311
+ .back-btn {
312
+ display: inline-flex;
313
+ align-items: center;
314
+ gap: 6px;
315
+ color: var(--muted);
316
+ text-decoration: none;
317
+ font-size: 13px;
318
+ font-weight: 600;
319
+ transition: color 0.2s;
320
+ margin-bottom: 20px;
321
+ }
322
+
323
+ .back-btn:hover {
324
+ color: #fff;
325
+ }
326
+
327
+ .controls-hint {
328
+ display: grid;
329
+ grid-template-columns: 1fr 1fr;
330
+ gap: 12px;
331
+ margin-top: 8px;
332
+ }
333
+ .key {
334
+ display: inline-block;
335
+ background: #1e293b;
336
+ border: 1px solid #334155;
337
+ border-radius: 4px;
338
+ padding: 2px 6px;
339
+ font-family: monospace;
340
+ font-size: 11px;
341
+ color: #cbd5e1;
342
+ box-shadow: 0 2px 0 #0f172a;
343
+ }
344
+
345
+ /* Hide standard canvas outline since we use hardware bezel */
346
+ #screen {
347
+ outline: none !important;
348
+ box-shadow: none !important;
349
+ }
350
+
351
+ /* Responsive Layout for Mobile */
352
+ @media (max-width: 900px) {
353
+ body,
354
+ html {
355
+ height: auto;
356
+ overflow-y: auto;
357
+ }
358
+
359
+ .shell {
360
+ display: flex;
361
+ flex-direction: column;
362
+ height: auto;
363
+ }
364
+
365
+ .stage {
366
+ padding: 10px;
367
+ min-height: auto;
368
+ }
369
+
370
+ .hardware-bezel {
371
+ padding: 15px 15px 40px 15px;
372
+ width: 100%;
373
+ box-sizing: border-box;
374
+ border-radius: 12px;
375
+ }
376
+
377
+ .panel {
378
+ border-left: none;
379
+ border-top: 1px solid var(--border);
380
+ padding: 20px 16px;
381
+ }
382
+
383
+ canvas {
384
+ max-height: 50vh;
385
+ }
386
+
387
+ /* Show mobile controls */
388
+ .mobile-controls {
389
+ display: flex !important;
390
+ }
391
+ }
392
+
393
+ /* Mobile Controls Styling */
394
+ .mobile-controls {
395
+ display: none; /* hidden on desktop */
396
+ width: 100%;
397
+ max-width: 1280px;
398
+ margin-top: 20px;
399
+ justify-content: space-between;
400
+ align-items: center;
401
+ padding: 0 10px;
402
+ user-select: none;
403
+ -webkit-user-select: none;
404
+ touch-action: none;
405
+ }
406
+
407
+ .d-pad,
408
+ .action-buttons {
409
+ display: grid;
410
+ gap: 8px;
411
+ align-items: center;
412
+ justify-content: center;
413
+ }
414
+
415
+ .d-pad {
416
+ grid-template-columns: repeat(3, 50px);
417
+ grid-template-rows: repeat(3, 50px);
418
+ }
419
+
420
+ .action-buttons {
421
+ grid-template-columns: repeat(2, 60px);
422
+ grid-template-rows: repeat(2, 60px);
423
+ transform: rotate(-15deg);
424
+ }
425
+
426
+ .btn-touch {
427
+ background: rgba(255, 255, 255, 0.1);
428
+ border: 2px solid rgba(255, 255, 255, 0.2);
429
+ border-radius: 12px;
430
+ color: rgba(255, 255, 255, 0.8);
431
+ font-family: 'Inter', sans-serif;
432
+ font-weight: bold;
433
+ font-size: 16px;
434
+ display: flex;
435
+ justify-content: center;
436
+ align-items: center;
437
+ box-shadow:
438
+ 0 4px 6px rgba(0, 0, 0, 0.4),
439
+ inset 0 2px 4px rgba(255, 255, 255, 0.1);
440
+ cursor: pointer;
441
+ /* Touch specific */
442
+ user-select: none;
443
+ -webkit-user-select: none;
444
+ touch-action: none;
445
+ }
446
+
447
+ .btn-touch:active,
448
+ .btn-touch.active {
449
+ background: rgba(14, 165, 233, 0.4);
450
+ border-color: rgba(14, 165, 233, 0.8);
451
+ transform: translateY(2px);
452
+ box-shadow:
453
+ 0 1px 2px rgba(0, 0, 0, 0.4),
454
+ inset 0 2px 4px rgba(0, 0, 0, 0.6);
455
+ }
456
+
457
+ .btn-up {
458
+ grid-column: 2;
459
+ grid-row: 1;
460
+ border-radius: 8px 8px 4px 4px;
461
+ }
462
+ .btn-down {
463
+ grid-column: 2;
464
+ grid-row: 3;
465
+ border-radius: 4px 4px 8px 8px;
466
+ }
467
+ .btn-left {
468
+ grid-column: 1;
469
+ grid-row: 2;
470
+ border-radius: 8px 4px 4px 8px;
471
+ }
472
+ .btn-right {
473
+ grid-column: 3;
474
+ grid-row: 2;
475
+ border-radius: 4px 8px 8px 4px;
476
+ }
477
+ .btn-center {
478
+ grid-column: 2;
479
+ grid-row: 2;
480
+ border-radius: 4px;
481
+ border: none;
482
+ background: rgba(255, 255, 255, 0.05);
483
+ }
484
+
485
+ .btn-a {
486
+ grid-column: 2;
487
+ grid-row: 1;
488
+ border-radius: 50%;
489
+ font-size: 20px;
490
+ background: rgba(244, 63, 94, 0.2);
491
+ border-color: rgba(244, 63, 94, 0.4);
492
+ }
493
+ .btn-a:active,
494
+ .btn-a.active {
495
+ background: rgba(244, 63, 94, 0.5);
496
+ }
497
+ .btn-b {
498
+ grid-column: 1;
499
+ grid-row: 2;
500
+ border-radius: 50%;
501
+ font-size: 20px;
502
+ background: rgba(168, 85, 247, 0.2);
503
+ border-color: rgba(168, 85, 247, 0.4);
504
+ }
505
+ .btn-b:active,
506
+ .btn-b.active {
507
+ background: rgba(168, 85, 247, 0.5);
508
+ }
509
+ </style>
510
+ <script type="importmap">
511
+ {
512
+ "imports": {
513
+ "three": "https://esm.sh/three@0.182.0",
514
+ "three/examples/jsm/": "https://esm.sh/three@0.182.0/examples/jsm/"
515
+ }
516
+ }
517
+ </script>
518
+ <script type="module" crossorigin src="./assets/console-CY_kygm3.js"></script>
519
+ </head>
520
+ <body>
521
+ <div class="shell">
522
+ <div class="stage">
523
+ <div class="hardware-bezel">
524
+ <div class="screen-container">
525
+ <canvas id="screen" width="1280" height="720"></canvas>
526
+ <div class="scanlines"></div>
527
+ <div class="screen-glare"></div>
528
+ </div>
529
+ <div class="hardware-brand">NOVA-64</div>
530
+ </div>
531
+
532
+ <!-- Mobile Virtual Controls -->
533
+ <div class="mobile-controls">
534
+ <div class="d-pad">
535
+ <div class="btn-touch btn-up" data-keys='["ArrowUp", "KeyW"]'>▲</div>
536
+ <div class="btn-touch btn-left" data-keys='["ArrowLeft", "KeyA"]'>◀</div>
537
+ <div class="btn-center"></div>
538
+ <div class="btn-touch btn-right" data-keys='["ArrowRight", "KeyD"]'>▶</div>
539
+ <div class="btn-touch btn-down" data-keys='["ArrowDown", "KeyS"]'>▼</div>
540
+ </div>
541
+ <div class="action-buttons">
542
+ <div class="btn-touch btn-a" data-keys='["Space", "Enter"]'>A</div>
543
+ <div class="btn-touch btn-b" data-keys='["KeyZ", "KeyX"]'>B</div>
544
+ </div>
545
+ </div>
546
+ </div>
547
+ <div class="panel">
548
+ <div>
549
+ <a href="/" class="back-btn">
550
+ <svg
551
+ width="16"
552
+ height="16"
553
+ viewBox="0 0 24 24"
554
+ fill="none"
555
+ stroke="currentColor"
556
+ stroke-width="2"
557
+ stroke-linecap="round"
558
+ stroke-linejoin="round"
559
+ >
560
+ <line x1="19" y1="12" x2="5" y2="12"></line>
561
+ <polyline points="12 19 5 12 12 5"></polyline>
562
+ </svg>
563
+ BACK TO DASHBOARD
564
+ </a>
565
+ <div class="title">NOVA-64 STUDIO</div>
566
+ <div class="subtitle">Ultimate 3D Web Engine<br />Hardware-accelerated environment</div>
567
+ </div>
568
+
569
+ <div class="hr"></div>
570
+
571
+ <div class="stat-box">
572
+ <span id="stats">FPS: 00 | UP: 00ms | DW: 00ms</span>
573
+ </div>
574
+
575
+ <div class="col">
576
+ <label>Cartridge Selection</label>
577
+ <select id="cart">
578
+ <option value="/examples/hello-world/code.js">⭐ Hello World (Start Here)</option>
579
+ <option value="/examples/space-harrier-3d/code.js">
580
+ 🛸 Space Harrier (2.5D Rail Shooter)
581
+ </option>
582
+ <option value="/examples/hello-3d/code.js">👋 Hello 3D World (Basic Demo)</option>
583
+ <option value="/examples/crystal-cathedral-3d/code.js">
584
+ 🏛️ Crystal Cathedral (Graphics)
585
+ </option>
586
+ <option value="/examples/mystical-realm-3d/code.js">🏰 Mystical Realm (World)</option>
587
+ <option value="/examples/star-fox-nova-3d/code.js">
588
+ 🚀 Star Fox Nova (Space Combat)
589
+ </option>
590
+ <option value="/examples/f-zero-nova-3d/code.js">🏁 F-Zero Nova (Racing)</option>
591
+ <option value="/examples/cyberpunk-city-3d/code.js">
592
+ 🌃 Cyberpunk City (Open World)
593
+ </option>
594
+ <option value="/examples/fps-demo-3d/code.js">🔫 FPS Action Mode (Shooter)</option>
595
+ <option value="/examples/adventure-comic-3d/code.js">
596
+ 🕵️ The Verdict (Comic Adventure)
597
+ </option>
598
+ <option value="/examples/physics-demo-3d/code.js">⚛️ Physics Lab (Simulation)</option>
599
+ <option value="/examples/shooter-demo-3d/code.js">🔫 Space Shooter (Combat)</option>
600
+ <option value="/examples/strider-demo-3d/code.js">⚔️ Gauntlet 64 (Isometric Action RPG)</option>
601
+ <option value="/examples/super-plumber-64/code.js">🍄 Super Plumber 64 (Platformer)</option>
602
+ <option value="/examples/minecraft-demo/code.js">⛏️ Minecraft Voxel World (Sandbox)</option>
603
+ <option value="/examples/dungeon-crawler-3d/code.js">🏰 Dungeon Crawler (Roguelike RPG)</option>
604
+ <option value="/examples/wizardry-3d/code.js">🧙 Wizardry (First-Person Dungeon RPG)</option>
605
+ <option value="/examples/boids-flocking/code.js">🐦 Boids Flocking (Generative Art)</option>
606
+ <option value="/examples/game-of-life-3d/code.js">🧬 Game of Life 3D (Cellular Automata)</option>
607
+ <option value="/examples/nature-explorer-3d/code.js">🌿 Nature Explorer (GLB Walking Sim)</option>
608
+ <option value="/examples/generative-art/code.js">🎨 Generative Art (Processing-style)</option>
609
+ <option value="/examples/3d-advanced/code.js">🎯 Advanced 3D (Technical)</option>
610
+ <option value="/examples/model-viewer-3d/code.js">🦊 Animated 3D Models</option>
611
+ <option value="/examples/demoscene/code.js">🎬 Demoscene - Tron (Showcase)</option>
612
+ <option value="/examples/hello-skybox/code.js">🌌 Nova Drift (Space Explorer)</option>
613
+ <option value="/examples/space-combat-3d/code.js">🛸 Space Combat 3D (Dogfight)</option>
614
+ <option value="/examples/input-showcase/code.js">
615
+ 🎮 Input Showcase (All Controls)
616
+ </option>
617
+ <option value="/examples/audio-lab/code.js">🔊 Audio Lab (Spatial Sound)</option>
618
+ <option value="/examples/storage-quest/code.js">
619
+ 💾 Storage Quest (Persistent Data)
620
+ </option>
621
+ <option value="/examples/instancing-demo/code.js">
622
+ ⚡ Instancing Demo (GPU Instancing + LOD)
623
+ </option>
624
+ <option value="/examples/particles-demo/code.js">
625
+ ✨ Particles Demo (GPU Particle System)
626
+ </option>
627
+ <option value="/examples/screen-demo/code.js">
628
+ 🖥️ Screen Demo (Multi-Screen System)
629
+ </option>
630
+ <option value="/examples/ui-demo/code.js">🎨 UI Demo (Interface Components)</option>
631
+ <option value="/examples/wing-commander-space/code.js">
632
+ 🚀 Wing Commander Space (Combat)
633
+ </option>
634
+ <option value="/examples/pbr-showcase/code.js">🔮 PBR Showcase (Materials)</option>
635
+ </select>
636
+ </div>
637
+
638
+ <div class="row" style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px">
639
+ <button id="pause" title="Pause Engine" class="btn-primary">
640
+ <svg
641
+ width="14"
642
+ height="14"
643
+ viewBox="0 0 24 24"
644
+ fill="none"
645
+ stroke="currentColor"
646
+ stroke-width="2"
647
+ >
648
+ <rect x="6" y="4" width="4" height="16"></rect>
649
+ <rect x="14" y="4" width="4" height="16"></rect>
650
+ </svg>
651
+ Hold
652
+ </button>
653
+ <button id="step" title="Step Frame" class="btn-primary">
654
+ <svg
655
+ width="14"
656
+ height="14"
657
+ viewBox="0 0 24 24"
658
+ fill="none"
659
+ stroke="currentColor"
660
+ stroke-width="2"
661
+ >
662
+ <polygon points="5 4 15 12 5 20 5 4"></polygon>
663
+ <line x1="19" y1="5" x2="19" y2="19"></line>
664
+ </svg>
665
+ Step
666
+ </button>
667
+ <button id="shot" title="Screenshot Canvas" class="btn-primary">
668
+ <svg
669
+ width="14"
670
+ height="14"
671
+ viewBox="0 0 24 24"
672
+ fill="none"
673
+ stroke="currentColor"
674
+ stroke-width="2"
675
+ >
676
+ <path
677
+ d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"
678
+ ></path>
679
+ <circle cx="12" cy="13" r="4"></circle>
680
+ </svg>
681
+ Snap
682
+ </button>
683
+ </div>
684
+ <button id="fullscreen" title="Toggle Fullscreen" style="width: 100%">
685
+ <svg
686
+ width="14"
687
+ height="14"
688
+ viewBox="0 0 24 24"
689
+ fill="none"
690
+ stroke="currentColor"
691
+ stroke-width="2"
692
+ >
693
+ <polyline points="15 3 21 3 21 9"></polyline>
694
+ <polyline points="9 21 3 21 3 15"></polyline>
695
+ <line x1="21" y1="3" x2="14" y2="10"></line>
696
+ <line x1="3" y1="21" x2="10" y2="14"></line>
697
+ </svg>
698
+ Fullscreen
699
+ </button>
700
+
701
+ <div class="hr"></div>
702
+
703
+ <div class="col">
704
+ <label>Development Array</label>
705
+ <button
706
+ id="editor"
707
+ onclick="window.open('/os9-shell/index.html?app=sprite-editor', '_blank')"
708
+ class="btn-magic"
709
+ >
710
+ <svg
711
+ width="16"
712
+ height="16"
713
+ viewBox="0 0 24 24"
714
+ fill="none"
715
+ stroke="currentColor"
716
+ stroke-width="2"
717
+ >
718
+ <path d="M12 19l7-7 3 3-7 7-3-3z"></path>
719
+ <path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path>
720
+ <path d="M2 2l7.586 7.586"></path>
721
+ <circle cx="11" cy="11" r="2"></circle>
722
+ </svg>
723
+ Asset Studio
724
+ </button>
725
+ <button id="os-shell" onclick="window.open('/os9-shell/index.html', '_blank')">
726
+ <svg
727
+ width="16"
728
+ height="16"
729
+ viewBox="0 0 24 24"
730
+ fill="none"
731
+ stroke="currentColor"
732
+ stroke-width="2"
733
+ >
734
+ <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
735
+ <line x1="8" y1="21" x2="16" y2="21"></line>
736
+ <line x1="12" y1="17" x2="12" y2="21"></line>
737
+ </svg>
738
+ NovaOS Desktop
739
+ </button>
740
+ <button id="docs" onclick="window.open('/docs/index.html', '_blank')">
741
+ <svg
742
+ width="16"
743
+ height="16"
744
+ viewBox="0 0 24 24"
745
+ fill="none"
746
+ stroke="currentColor"
747
+ stroke-width="2"
748
+ >
749
+ <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
750
+ <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
751
+ </svg>
752
+ Engine Syntax
753
+ </button>
754
+ </div>
755
+
756
+ <div class="footer">
757
+ <div style="margin-bottom: 8px; color: #fff; font-weight: 600; text-transform: uppercase">
758
+ Controls
759
+ </div>
760
+ <div class="controls-hint">
761
+ <div>
762
+ <span class="key">W</span><span class="key">A</span><span class="key">S</span
763
+ ><span class="key">D</span> Move
764
+ </div>
765
+ <div>
766
+ <span class="key">↑</span><span class="key">↓</span><span class="key">←</span
767
+ ><span class="key">→</span> Move
768
+ </div>
769
+ <div><span class="key">Z</span><span class="key">X</span> Button</div>
770
+ <div><span class="key">Space</span> Action</div>
771
+ </div>
772
+ </div>
773
+ </div>
774
+ </div>
775
+
776
+
777
+ <script>
778
+ // Virtual controls code mapper
779
+ function handleVirtualButton(element, isDown) {
780
+ if (!element || !element.dataset || !element.dataset.keys) return;
781
+ try {
782
+ const keys = JSON.parse(element.dataset.keys);
783
+ keys.forEach(code => {
784
+ window.dispatchEvent(
785
+ new KeyboardEvent(isDown ? 'keydown' : 'keyup', { code, bubbles: true })
786
+ );
787
+ });
788
+ if (isDown) {
789
+ element.classList.add('active');
790
+ } else {
791
+ element.classList.remove('active');
792
+ }
793
+ } catch (e) {
794
+ console.error('Virtual input error:', e);
795
+ }
796
+ }
797
+
798
+ // Bind touch events to on-screen buttons
799
+ document.querySelectorAll('.btn-touch').forEach(btn => {
800
+ // Prevent default double-tap zoom or context menus
801
+ btn.addEventListener('contextmenu', e => e.preventDefault());
802
+
803
+ btn.addEventListener(
804
+ 'touchstart',
805
+ e => {
806
+ e.preventDefault(); // Stop mouse fallback events
807
+ handleVirtualButton(e.currentTarget, true);
808
+ },
809
+ { passive: false }
810
+ );
811
+
812
+ btn.addEventListener(
813
+ 'touchend',
814
+ e => {
815
+ e.preventDefault();
816
+ handleVirtualButton(e.currentTarget, false);
817
+ },
818
+ { passive: false }
819
+ );
820
+
821
+ btn.addEventListener(
822
+ 'touchcancel',
823
+ e => {
824
+ e.preventDefault();
825
+ handleVirtualButton(e.currentTarget, false);
826
+ },
827
+ { passive: false }
828
+ );
829
+
830
+ // Add mouse support just in case someone clicks them on desktop to test
831
+ btn.addEventListener('mousedown', e => {
832
+ e.preventDefault();
833
+ handleVirtualButton(e.currentTarget, true);
834
+ });
835
+ btn.addEventListener('mouseup', e => {
836
+ e.preventDefault();
837
+ handleVirtualButton(e.currentTarget, false);
838
+ });
839
+ btn.addEventListener('mouseleave', e => {
840
+ e.preventDefault();
841
+ if (btn.classList.contains('active')) {
842
+ handleVirtualButton(e.currentTarget, false);
843
+ }
844
+ });
845
+ });
846
+
847
+ // Fullscreen toggle
848
+ document.getElementById('fullscreen').addEventListener('click', () => {
849
+ const target = document.querySelector('.hardware-bezel');
850
+ if (!document.fullscreenElement) {
851
+ target.requestFullscreen().catch(() => {});
852
+ } else {
853
+ document.exitFullscreen();
854
+ }
855
+ });
856
+ document.addEventListener('fullscreenchange', () => {
857
+ const btn = document.getElementById('fullscreen');
858
+ const isFullscreen = !!document.fullscreenElement;
859
+ btn.innerHTML = isFullscreen
860
+ ? '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 14 10 14 10 20"></polyline><polyline points="20 10 14 10 14 4"></polyline><line x1="10" y1="14" x2="3" y2="21"></line><line x1="21" y1="3" x2="14" y2="10"></line></svg> Exit Full'
861
+ : '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg> Fullscreen';
862
+ });
863
+
864
+ const urlParams = new URLSearchParams(window.location.search);
865
+ const demoParam = urlParams.get('demo');
866
+ if (demoParam) {
867
+ window.addEventListener('load', () => {
868
+ const select = document.getElementById('cart');
869
+ const demoMap = {
870
+ 'crystal-cathedral-3d': '/examples/crystal-cathedral-3d/code.js',
871
+ 'f-zero-nova-3d': '/examples/f-zero-nova-3d/code.js',
872
+ 'star-fox-nova-3d': '/examples/star-fox-nova-3d/code.js',
873
+ 'minecraft-demo': '/examples/minecraft-demo/code.js',
874
+ 'super-plumber-64': '/examples/super-plumber-64/code.js',
875
+ 'cyberpunk-city-3d': '/examples/cyberpunk-city-3d/code.js',
876
+ 'strider-demo-3d': '/examples/strider-demo-3d/code.js',
877
+ 'model-viewer-3d': '/examples/model-viewer-3d/code.js',
878
+ demoscene: '/examples/demoscene/code.js',
879
+ 'space-harrier-3d': '/examples/space-harrier-3d/code.js',
880
+ 'hello-3d': '/examples/hello-3d/code.js',
881
+ 'mystical-realm-3d': '/examples/mystical-realm-3d/code.js',
882
+ 'physics-demo-3d': '/examples/physics-demo-3d/code.js',
883
+ 'shooter-demo-3d': '/examples/shooter-demo-3d/code.js',
884
+ 'hello-skybox': '/examples/hello-skybox/code.js',
885
+ 'fps-demo-3d': '/examples/fps-demo-3d/code.js',
886
+ 'adventure-comic-3d': '/examples/adventure-comic-3d/code.js',
887
+ '3d-advanced': '/examples/3d-advanced/code.js',
888
+ 'space-combat-3d': '/examples/space-combat-3d/code.js',
889
+ 'wing-commander-space': '/examples/wing-commander-space/code.js',
890
+ 'pbr-showcase': '/examples/pbr-showcase/code.js',
891
+ };
892
+ if (demoMap[demoParam]) {
893
+ select.value = demoMap[demoParam];
894
+ }
895
+ });
896
+ }
897
+ </script>
898
+ </body>
899
+ </html>