nova64 0.2.1
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.
- package/LICENSE +21 -0
- package/README.md +786 -0
- package/index.html +651 -0
- package/package.json +255 -0
- package/public/os9-shell/assets/index-B1Uvacma.js +32825 -0
- package/public/os9-shell/assets/index-B1Uvacma.js.map +1 -0
- package/public/os9-shell/assets/index-DIHfrTaW.css +1 -0
- package/public/os9-shell/index.html +14 -0
- package/public/os9-shell/nova-icon.svg +12 -0
- package/runtime/api-2d.js +878 -0
- package/runtime/api-3d/camera.js +73 -0
- package/runtime/api-3d/instancing.js +180 -0
- package/runtime/api-3d/lights.js +51 -0
- package/runtime/api-3d/materials.js +47 -0
- package/runtime/api-3d/models.js +84 -0
- package/runtime/api-3d/pbr.js +69 -0
- package/runtime/api-3d/primitives.js +304 -0
- package/runtime/api-3d/scene.js +169 -0
- package/runtime/api-3d/transforms.js +161 -0
- package/runtime/api-3d.js +154 -0
- package/runtime/api-effects.js +753 -0
- package/runtime/api-presets.js +85 -0
- package/runtime/api-skybox.js +178 -0
- package/runtime/api-sprites.js +100 -0
- package/runtime/api-voxel.js +601 -0
- package/runtime/api.js +201 -0
- package/runtime/assets.js +27 -0
- package/runtime/audio.js +114 -0
- package/runtime/collision.js +47 -0
- package/runtime/console.js +101 -0
- package/runtime/editor.js +233 -0
- package/runtime/font.js +233 -0
- package/runtime/framebuffer.js +28 -0
- package/runtime/fullscreen-button.js +185 -0
- package/runtime/gpu-canvas2d.js +47 -0
- package/runtime/gpu-threejs.js +639 -0
- package/runtime/gpu-webgl2.js +310 -0
- package/runtime/index.js +22 -0
- package/runtime/input.js +225 -0
- package/runtime/logger.js +60 -0
- package/runtime/physics.js +101 -0
- package/runtime/screens.js +213 -0
- package/runtime/storage.js +38 -0
- package/runtime/store.js +151 -0
- package/runtime/textinput.js +68 -0
- package/runtime/ui/buttons.js +124 -0
- package/runtime/ui/panels.js +105 -0
- package/runtime/ui/text.js +86 -0
- package/runtime/ui/widgets.js +141 -0
- package/runtime/ui.js +111 -0
- package/src/main.js +474 -0
- package/vite.config.js +63 -0
package/src/main.js
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import { Nova64 } from '../runtime/console.js';
|
|
2
|
+
import { GpuThreeJS } from '../runtime/gpu-threejs.js';
|
|
3
|
+
import { logger } from '../runtime/logger.js';
|
|
4
|
+
globalThis.novaLogger = logger;
|
|
5
|
+
import { stdApi } from '../runtime/api.js';
|
|
6
|
+
import { spriteApi } from '../runtime/api-sprites.js';
|
|
7
|
+
import { threeDApi } from '../runtime/api-3d.js';
|
|
8
|
+
import { editorApi } from '../runtime/editor.js';
|
|
9
|
+
import { physicsApi } from '../runtime/physics.js';
|
|
10
|
+
import { textInputApi } from '../runtime/textinput.js';
|
|
11
|
+
import { aabb, circle as circleCollision, raycastTilemap } from '../runtime/collision.js';
|
|
12
|
+
import { audioApi } from '../runtime/audio.js';
|
|
13
|
+
import { inputApi } from '../runtime/input.js';
|
|
14
|
+
import { storageApi } from '../runtime/storage.js';
|
|
15
|
+
import { screenApi } from '../runtime/screens.js';
|
|
16
|
+
import { skyboxApi } from '../runtime/api-skybox.js';
|
|
17
|
+
import { uiApi } from '../runtime/ui.js';
|
|
18
|
+
import { effectsApi } from '../runtime/api-effects.js';
|
|
19
|
+
import { voxelApi } from '../runtime/api-voxel.js';
|
|
20
|
+
import { createFullscreenButton } from '../runtime/fullscreen-button.js';
|
|
21
|
+
import { storeApi } from '../runtime/store.js';
|
|
22
|
+
import { api2d } from '../runtime/api-2d.js';
|
|
23
|
+
import { presetsApi } from '../runtime/api-presets.js';
|
|
24
|
+
|
|
25
|
+
const canvas = document.getElementById('screen');
|
|
26
|
+
|
|
27
|
+
// Create fullscreen button - stored globally for cleanup if needed
|
|
28
|
+
globalThis.fullscreenButton = createFullscreenButton(canvas);
|
|
29
|
+
|
|
30
|
+
// ONLY use Three.js renderer - Nintendo 64/PlayStation style 3D console
|
|
31
|
+
let gpu;
|
|
32
|
+
try {
|
|
33
|
+
gpu = new GpuThreeJS(canvas, 640, 360);
|
|
34
|
+
console.log('â
Using Three.js renderer - Nintendo 64/PlayStation GPU mode');
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.error('â Three.js renderer failed to initialize:', e);
|
|
37
|
+
throw new Error('Fantasy console requires 3D GPU support (Three.js)');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const api = stdApi(gpu);
|
|
41
|
+
const sApi = spriteApi(gpu);
|
|
42
|
+
const threeDApi_instance = threeDApi(gpu);
|
|
43
|
+
const eApi = editorApi(sApi);
|
|
44
|
+
const pApi = physicsApi();
|
|
45
|
+
const tApi = textInputApi();
|
|
46
|
+
const aApi = audioApi();
|
|
47
|
+
const iApi = inputApi();
|
|
48
|
+
const stApi = storageApi('nova64');
|
|
49
|
+
const scrApi = screenApi();
|
|
50
|
+
const skyApi = skyboxApi(gpu);
|
|
51
|
+
const fxApi = effectsApi(gpu);
|
|
52
|
+
const vxApi = voxelApi(gpu);
|
|
53
|
+
const storeApiInst = storeApi();
|
|
54
|
+
const api2dInst = api2d(gpu);
|
|
55
|
+
const presetsInst = presetsApi(gpu);
|
|
56
|
+
|
|
57
|
+
// Create UI API - needs to be created after api is fully initialized
|
|
58
|
+
let uiApiInstance;
|
|
59
|
+
|
|
60
|
+
// gather and expose to global
|
|
61
|
+
const g = {};
|
|
62
|
+
api.exposeTo(g);
|
|
63
|
+
sApi.exposeTo(g);
|
|
64
|
+
threeDApi_instance.exposeTo(g);
|
|
65
|
+
eApi.exposeTo(g);
|
|
66
|
+
pApi.exposeTo(g);
|
|
67
|
+
tApi.exposeTo(g);
|
|
68
|
+
Object.assign(g, { aabb, circleCollision, raycastTilemap });
|
|
69
|
+
aApi.exposeTo(g);
|
|
70
|
+
iApi.exposeTo(g);
|
|
71
|
+
stApi.exposeTo(g);
|
|
72
|
+
scrApi.exposeTo(g);
|
|
73
|
+
skyApi.exposeTo(g);
|
|
74
|
+
fxApi.exposeTo(g);
|
|
75
|
+
vxApi.exposeTo(g);
|
|
76
|
+
storeApiInst.exposeTo(g);
|
|
77
|
+
api2dInst.exposeTo(g);
|
|
78
|
+
presetsInst.exposeTo(g);
|
|
79
|
+
|
|
80
|
+
// Now create UI API after g has rgba8 and other functions
|
|
81
|
+
uiApiInstance = uiApi(gpu, g);
|
|
82
|
+
uiApiInstance.exposeTo(g);
|
|
83
|
+
|
|
84
|
+
// Connect input system to UI system for mouse events
|
|
85
|
+
iApi.connectUI(uiApiInstance.setMousePosition, uiApiInstance.setMouseButton);
|
|
86
|
+
|
|
87
|
+
Object.assign(globalThis, g);
|
|
88
|
+
// inject camera ref into sprite system
|
|
89
|
+
if (g.getCamera) sApi.setCameraRef(g.getCamera());
|
|
90
|
+
|
|
91
|
+
const nova = new Nova64(gpu);
|
|
92
|
+
|
|
93
|
+
let paused = false;
|
|
94
|
+
let stepOnce = false;
|
|
95
|
+
let statsEl = document.getElementById('stats');
|
|
96
|
+
|
|
97
|
+
async function loadCart(path) {
|
|
98
|
+
await nova.loadCart(path);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function attachUI() {
|
|
102
|
+
const sel = document.getElementById('cart');
|
|
103
|
+
const pauseBtn = document.getElementById('pause');
|
|
104
|
+
const stepBtn = document.getElementById('step');
|
|
105
|
+
const shotBtn = document.getElementById('shot');
|
|
106
|
+
|
|
107
|
+
sel.addEventListener('change', async () => {
|
|
108
|
+
paused = false;
|
|
109
|
+
pauseBtn.textContent = 'Pause';
|
|
110
|
+
await loadCart(sel.value);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Renderer is now fixed to Three.js only - no UI controls needed
|
|
114
|
+
// Editor button now handled by inline onclick in HTML to open OS9 shell
|
|
115
|
+
|
|
116
|
+
pauseBtn.addEventListener('click', () => {
|
|
117
|
+
paused = !paused;
|
|
118
|
+
pauseBtn.textContent = paused ? 'Resume' : 'Pause';
|
|
119
|
+
});
|
|
120
|
+
stepBtn.addEventListener('click', () => {
|
|
121
|
+
stepOnce = true;
|
|
122
|
+
});
|
|
123
|
+
shotBtn.addEventListener('click', () => {
|
|
124
|
+
const url = canvas.toDataURL('image/png');
|
|
125
|
+
const a = document.createElement('a');
|
|
126
|
+
a.href = url;
|
|
127
|
+
a.download = 'nova64.png';
|
|
128
|
+
a.click();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let last = performance.now();
|
|
133
|
+
let uMs = 0,
|
|
134
|
+
dMs = 0,
|
|
135
|
+
fps = 0;
|
|
136
|
+
let currentDt = 0;
|
|
137
|
+
|
|
138
|
+
// Expose timing functions globally
|
|
139
|
+
globalThis.getDeltaTime = () => currentDt;
|
|
140
|
+
globalThis.getFPS = () => fps;
|
|
141
|
+
|
|
142
|
+
function loop() {
|
|
143
|
+
const now = performance.now();
|
|
144
|
+
const dt = Math.min(0.1, (now - last) / 1000);
|
|
145
|
+
currentDt = dt;
|
|
146
|
+
last = now;
|
|
147
|
+
|
|
148
|
+
if (!paused || stepOnce) {
|
|
149
|
+
iApi.step();
|
|
150
|
+
const u0 = performance.now();
|
|
151
|
+
|
|
152
|
+
// Tick the global novaStore time counter
|
|
153
|
+
storeApiInst.tick(dt);
|
|
154
|
+
// Auto-animate skybox if enabled
|
|
155
|
+
skyApi._tick(dt);
|
|
156
|
+
// Update post-processing shader uniforms (time, etc.)
|
|
157
|
+
fxApi.update(dt);
|
|
158
|
+
|
|
159
|
+
// Update cart first (for manual screen management)
|
|
160
|
+
// Check if cart exists to prevent errors during scene transitions
|
|
161
|
+
if (nova.cart && nova.cart.update) {
|
|
162
|
+
try {
|
|
163
|
+
if (typeof globalThis.updateAnimations === 'function') {
|
|
164
|
+
globalThis.updateAnimations(dt);
|
|
165
|
+
}
|
|
166
|
+
nova.cart.update(dt);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.error('â Cart update() error:', e.message);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Then update screen manager (for automatic screen management)
|
|
173
|
+
scrApi.manager.update(dt);
|
|
174
|
+
|
|
175
|
+
const u1 = performance.now();
|
|
176
|
+
uMs = u1 - u0;
|
|
177
|
+
|
|
178
|
+
gpu.beginFrame();
|
|
179
|
+
const d0 = performance.now();
|
|
180
|
+
|
|
181
|
+
// Draw cart first (for manual rendering)
|
|
182
|
+
// Check if cart exists to prevent errors during scene transitions
|
|
183
|
+
if (nova.cart && nova.cart.draw) {
|
|
184
|
+
try {
|
|
185
|
+
nova.cart.draw();
|
|
186
|
+
} catch (e) {
|
|
187
|
+
console.error('â Cart draw() error:', e.message, e.stack);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Then draw screen manager (for automatic screen rendering)
|
|
192
|
+
scrApi.manager.draw();
|
|
193
|
+
|
|
194
|
+
const d1 = performance.now();
|
|
195
|
+
dMs = d1 - d0;
|
|
196
|
+
try {
|
|
197
|
+
gpu.endFrame();
|
|
198
|
+
} catch (e) {
|
|
199
|
+
console.error('â gpu.endFrame() error:', e.message, e.stack);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (stepOnce) {
|
|
203
|
+
stepOnce = false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fps = Math.round(1000 / (performance.now() - now));
|
|
207
|
+
|
|
208
|
+
// 3D GPU stats
|
|
209
|
+
let statsText = `3D GPU (Three.js) âĸ fps: ${fps}, update: ${uMs.toFixed(2)}ms, draw: ${dMs.toFixed(2)}ms`;
|
|
210
|
+
|
|
211
|
+
// Add 3D stats if available
|
|
212
|
+
if (typeof get3DStats === 'function') {
|
|
213
|
+
const stats3D = get3DStats();
|
|
214
|
+
if (stats3D.render) {
|
|
215
|
+
statsText += ` âĸ triangles: ${stats3D.render.triangles}, calls: ${stats3D.render.calls}`;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
statsEl.textContent = statsText;
|
|
220
|
+
requestAnimationFrame(loop);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
attachUI();
|
|
224
|
+
|
|
225
|
+
// Check for game parameter in URL
|
|
226
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
227
|
+
const gameParam = urlParams.get('game');
|
|
228
|
+
const gamePathParam = urlParams.get('path'); // Allow direct path parameter
|
|
229
|
+
const demoParam = urlParams.get('demo'); // Also handle ?demo= from console.html links
|
|
230
|
+
|
|
231
|
+
// Map game IDs to their paths
|
|
232
|
+
const gameMap = {
|
|
233
|
+
'space-harrier': '/examples/space-harrier-3d/code.js',
|
|
234
|
+
fzero: '/examples/f-zero-nova-3d/code.js',
|
|
235
|
+
knight: '/examples/strider-demo-3d/code.js',
|
|
236
|
+
cyberpunk: '/examples/cyberpunk-city-3d/code.js',
|
|
237
|
+
strider: '/examples/strider-demo-3d/code.js',
|
|
238
|
+
demoscene: '/examples/demoscene/code.js',
|
|
239
|
+
'space-combat': '/examples/star-fox-nova-3d/code.js',
|
|
240
|
+
minecraft: '/examples/minecraft-demo/code.js',
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Map demo names (from ?demo= URL param) to paths
|
|
244
|
+
const demoMap = {
|
|
245
|
+
'hello-world': '/examples/hello-world/code.js',
|
|
246
|
+
'crystal-cathedral-3d': '/examples/crystal-cathedral-3d/code.js',
|
|
247
|
+
'f-zero-nova-3d': '/examples/f-zero-nova-3d/code.js',
|
|
248
|
+
'star-fox-nova-3d': '/examples/star-fox-nova-3d/code.js',
|
|
249
|
+
'minecraft-demo': '/examples/minecraft-demo/code.js',
|
|
250
|
+
'super-plumber-64': '/examples/super-plumber-64/code.js',
|
|
251
|
+
'cyberpunk-city-3d': '/examples/cyberpunk-city-3d/code.js',
|
|
252
|
+
'strider-demo-3d': '/examples/strider-demo-3d/code.js',
|
|
253
|
+
demoscene: '/examples/demoscene/code.js',
|
|
254
|
+
'space-harrier-3d': '/examples/space-harrier-3d/code.js',
|
|
255
|
+
'hello-3d': '/examples/hello-3d/code.js',
|
|
256
|
+
'mystical-realm-3d': '/examples/mystical-realm-3d/code.js',
|
|
257
|
+
'physics-demo-3d': '/examples/physics-demo-3d/code.js',
|
|
258
|
+
'shooter-demo-3d': '/examples/shooter-demo-3d/code.js',
|
|
259
|
+
'hello-skybox': '/examples/hello-skybox/code.js',
|
|
260
|
+
'fps-demo-3d': '/examples/fps-demo-3d/code.js',
|
|
261
|
+
'adventure-comic-3d': '/examples/adventure-comic-3d/code.js',
|
|
262
|
+
'input-showcase': '/examples/input-showcase/code.js',
|
|
263
|
+
'audio-lab': '/examples/audio-lab/code.js',
|
|
264
|
+
'storage-quest': '/examples/storage-quest/code.js',
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// default cart - load from URL param or default to space-harrier-3d
|
|
268
|
+
(async () => {
|
|
269
|
+
let gamePath = document.getElementById('cart')?.value || '/examples/space-harrier-3d/code.js';
|
|
270
|
+
|
|
271
|
+
if (gamePathParam) {
|
|
272
|
+
gamePath = gamePathParam;
|
|
273
|
+
} else if (demoParam && demoMap[demoParam]) {
|
|
274
|
+
// Handle ?demo= parameter (from console.html links / index.html demo cards)
|
|
275
|
+
gamePath = demoMap[demoParam];
|
|
276
|
+
} else if (demoParam) {
|
|
277
|
+
// Fallback: try constructing path from demo name directly
|
|
278
|
+
gamePath = `/examples/${demoParam}/code.js`;
|
|
279
|
+
} else if (gameParam && gameMap[gameParam]) {
|
|
280
|
+
gamePath = gameMap[gameParam];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
console.log(`đŽ Loading game: ${gamePath}`);
|
|
284
|
+
await loadCart(gamePath);
|
|
285
|
+
requestAnimationFrame(loop);
|
|
286
|
+
})();
|
|
287
|
+
|
|
288
|
+
// Listen for messages from Game Studio to execute code
|
|
289
|
+
window.addEventListener('message', event => {
|
|
290
|
+
if (event.data && event.data.type === 'EXECUTE_CODE') {
|
|
291
|
+
console.log('đŽ Game Studio: Executing code...');
|
|
292
|
+
console.log('đ Code to execute:', event.data.code.substring(0, 200) + '...');
|
|
293
|
+
console.log('đ§ Available APIs:', {
|
|
294
|
+
api: typeof api,
|
|
295
|
+
iApi: typeof iApi,
|
|
296
|
+
threeDApi_instance: typeof threeDApi_instance,
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
// Stop current game loop if running
|
|
301
|
+
console.log('â¸ī¸ Pausing game...');
|
|
302
|
+
paused = true;
|
|
303
|
+
|
|
304
|
+
// Reset the 3D scene
|
|
305
|
+
console.log('đ§š Clearing 3D scene...');
|
|
306
|
+
if (threeDApi_instance && typeof threeDApi_instance.clearScene === 'function') {
|
|
307
|
+
threeDApi_instance.clearScene();
|
|
308
|
+
console.log('â
Scene cleared');
|
|
309
|
+
} else {
|
|
310
|
+
console.warn('â ī¸ clearScene not available');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Execute the new code
|
|
314
|
+
const userCode = event.data.code;
|
|
315
|
+
|
|
316
|
+
console.log('đ¨ Creating game function...');
|
|
317
|
+
// Create a function from the code and execute it
|
|
318
|
+
const gameFunction = new Function(
|
|
319
|
+
'cls',
|
|
320
|
+
'pset',
|
|
321
|
+
'pget',
|
|
322
|
+
'rectfill',
|
|
323
|
+
'rect',
|
|
324
|
+
'circfill',
|
|
325
|
+
'circ',
|
|
326
|
+
'line',
|
|
327
|
+
'print',
|
|
328
|
+
'btn',
|
|
329
|
+
'btnp',
|
|
330
|
+
'rgba8',
|
|
331
|
+
'spr',
|
|
332
|
+
'map',
|
|
333
|
+
'mset',
|
|
334
|
+
'mget',
|
|
335
|
+
'rect3d',
|
|
336
|
+
'cube3d',
|
|
337
|
+
'sphere3d',
|
|
338
|
+
'cylinder3d',
|
|
339
|
+
'cone3d',
|
|
340
|
+
'model3d',
|
|
341
|
+
'light3d',
|
|
342
|
+
'setCamera',
|
|
343
|
+
'lookAt',
|
|
344
|
+
'fog3d',
|
|
345
|
+
'clearScene',
|
|
346
|
+
'updateModel',
|
|
347
|
+
'createSpaceSkybox',
|
|
348
|
+
'animateSkybox',
|
|
349
|
+
'clearSkybox',
|
|
350
|
+
'bloom',
|
|
351
|
+
'chromaticAberration',
|
|
352
|
+
'vignette',
|
|
353
|
+
'scanlines',
|
|
354
|
+
'crt',
|
|
355
|
+
'glitch',
|
|
356
|
+
'createVoxelEngine',
|
|
357
|
+
'voxelSet',
|
|
358
|
+
'voxelGet',
|
|
359
|
+
'voxelClear',
|
|
360
|
+
'voxelRender',
|
|
361
|
+
'console',
|
|
362
|
+
'Math',
|
|
363
|
+
'Date',
|
|
364
|
+
'Array',
|
|
365
|
+
'Object',
|
|
366
|
+
'String',
|
|
367
|
+
'Number',
|
|
368
|
+
userCode +
|
|
369
|
+
'\n; return { update: typeof update !== "undefined" ? update : null, draw: typeof draw !== "undefined" ? draw : null, render: typeof render !== "undefined" ? render : null };'
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
console.log('đ Executing game function...');
|
|
373
|
+
// Call with the API functions and capture the returned functions
|
|
374
|
+
const gameFunctions = gameFunction(
|
|
375
|
+
api.cls,
|
|
376
|
+
api.pset,
|
|
377
|
+
api.pget,
|
|
378
|
+
api.rectfill,
|
|
379
|
+
api.rect,
|
|
380
|
+
api.circfill,
|
|
381
|
+
api.circ,
|
|
382
|
+
api.line,
|
|
383
|
+
api.print,
|
|
384
|
+
iApi.btn,
|
|
385
|
+
iApi.btnp,
|
|
386
|
+
api.rgba8,
|
|
387
|
+
sApi.spr,
|
|
388
|
+
sApi.map,
|
|
389
|
+
sApi.mset,
|
|
390
|
+
sApi.mget,
|
|
391
|
+
threeDApi_instance.rect3d,
|
|
392
|
+
threeDApi_instance.cube3d,
|
|
393
|
+
threeDApi_instance.sphere3d,
|
|
394
|
+
threeDApi_instance.cylinder3d,
|
|
395
|
+
threeDApi_instance.cone3d,
|
|
396
|
+
threeDApi_instance.model3d,
|
|
397
|
+
threeDApi_instance.light3d,
|
|
398
|
+
threeDApi_instance.setCamera,
|
|
399
|
+
threeDApi_instance.lookAt,
|
|
400
|
+
threeDApi_instance.fog3d,
|
|
401
|
+
threeDApi_instance.clearScene,
|
|
402
|
+
threeDApi_instance.updateModel,
|
|
403
|
+
g.createSpaceSkybox,
|
|
404
|
+
g.animateSkybox,
|
|
405
|
+
g.clearSkybox,
|
|
406
|
+
fxApi.bloom,
|
|
407
|
+
fxApi.chromaticAberration,
|
|
408
|
+
fxApi.vignette,
|
|
409
|
+
fxApi.scanlines,
|
|
410
|
+
fxApi.crt,
|
|
411
|
+
fxApi.glitch,
|
|
412
|
+
vxApi.createVoxelEngine,
|
|
413
|
+
vxApi.voxelSet,
|
|
414
|
+
vxApi.voxelGet,
|
|
415
|
+
vxApi.voxelClear,
|
|
416
|
+
vxApi.voxelRender,
|
|
417
|
+
console,
|
|
418
|
+
Math,
|
|
419
|
+
Date,
|
|
420
|
+
Array,
|
|
421
|
+
Object,
|
|
422
|
+
String,
|
|
423
|
+
Number
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
console.log('đ Game functions:', gameFunctions);
|
|
427
|
+
|
|
428
|
+
// Replace the cart's update/draw functions with the new ones
|
|
429
|
+
if (gameFunctions.update || gameFunctions.draw || gameFunctions.render) {
|
|
430
|
+
console.log('đ Replacing cart functions...');
|
|
431
|
+
if (!nova.cart) {
|
|
432
|
+
nova.cart = {};
|
|
433
|
+
}
|
|
434
|
+
if (gameFunctions.update) {
|
|
435
|
+
nova.cart.update = gameFunctions.update;
|
|
436
|
+
console.log('â
Replaced update function');
|
|
437
|
+
}
|
|
438
|
+
if (gameFunctions.draw) {
|
|
439
|
+
nova.cart.draw = gameFunctions.draw;
|
|
440
|
+
console.log('â
Replaced draw function');
|
|
441
|
+
} else if (gameFunctions.render) {
|
|
442
|
+
// Support both draw() and render() naming conventions
|
|
443
|
+
nova.cart.draw = gameFunctions.render;
|
|
444
|
+
console.log('â
Replaced draw function (from render)');
|
|
445
|
+
}
|
|
446
|
+
} else {
|
|
447
|
+
console.log('âšī¸ No update/draw functions found in code');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Resume the game loop
|
|
451
|
+
console.log('âļī¸ Resuming game loop...');
|
|
452
|
+
paused = false;
|
|
453
|
+
|
|
454
|
+
console.log('â
Game Studio: Code executed successfully!');
|
|
455
|
+
|
|
456
|
+
// Send success message back
|
|
457
|
+
if (event.source) {
|
|
458
|
+
event.source.postMessage({ type: 'EXECUTE_SUCCESS' }, event.origin);
|
|
459
|
+
}
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.error('â Game Studio: Error executing code:', error);
|
|
462
|
+
console.error('Stack trace:', error.stack);
|
|
463
|
+
if (event.source) {
|
|
464
|
+
event.source.postMessage(
|
|
465
|
+
{
|
|
466
|
+
type: 'EXECUTE_ERROR',
|
|
467
|
+
error: error.message,
|
|
468
|
+
},
|
|
469
|
+
event.origin
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
});
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
// Base path for deployment
|
|
6
|
+
base: './',
|
|
7
|
+
|
|
8
|
+
// Build configuration
|
|
9
|
+
build: {
|
|
10
|
+
target: 'es2022',
|
|
11
|
+
outDir: 'dist',
|
|
12
|
+
assetsDir: 'assets',
|
|
13
|
+
sourcemap: true,
|
|
14
|
+
|
|
15
|
+
// Optimize output
|
|
16
|
+
minify: 'terser',
|
|
17
|
+
terserOptions: {
|
|
18
|
+
compress: {
|
|
19
|
+
drop_console: false, // Keep console for debugging
|
|
20
|
+
drop_debugger: true,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Chunk size warnings
|
|
25
|
+
chunkSizeWarningLimit: 1000,
|
|
26
|
+
|
|
27
|
+
// Rollup options
|
|
28
|
+
rollupOptions: {
|
|
29
|
+
input: {
|
|
30
|
+
main: resolve(__dirname, 'index.html'),
|
|
31
|
+
console: resolve(__dirname, 'console.html'),
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// Dev server configuration
|
|
37
|
+
server: {
|
|
38
|
+
port: 5173,
|
|
39
|
+
open: true,
|
|
40
|
+
host: true, // Allow network access
|
|
41
|
+
|
|
42
|
+
// Hot module replacement
|
|
43
|
+
hmr: {
|
|
44
|
+
overlay: true,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Optimizations
|
|
49
|
+
optimizeDeps: {
|
|
50
|
+
include: ['three', 'zustand'],
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// Plugin configuration
|
|
54
|
+
plugins: [],
|
|
55
|
+
|
|
56
|
+
// Resolve configuration
|
|
57
|
+
resolve: {
|
|
58
|
+
alias: {
|
|
59
|
+
'@runtime': resolve(__dirname, 'runtime'),
|
|
60
|
+
'@examples': resolve(__dirname, 'examples'),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|