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.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +786 -0
  3. package/index.html +651 -0
  4. package/package.json +255 -0
  5. package/public/os9-shell/assets/index-B1Uvacma.js +32825 -0
  6. package/public/os9-shell/assets/index-B1Uvacma.js.map +1 -0
  7. package/public/os9-shell/assets/index-DIHfrTaW.css +1 -0
  8. package/public/os9-shell/index.html +14 -0
  9. package/public/os9-shell/nova-icon.svg +12 -0
  10. package/runtime/api-2d.js +878 -0
  11. package/runtime/api-3d/camera.js +73 -0
  12. package/runtime/api-3d/instancing.js +180 -0
  13. package/runtime/api-3d/lights.js +51 -0
  14. package/runtime/api-3d/materials.js +47 -0
  15. package/runtime/api-3d/models.js +84 -0
  16. package/runtime/api-3d/pbr.js +69 -0
  17. package/runtime/api-3d/primitives.js +304 -0
  18. package/runtime/api-3d/scene.js +169 -0
  19. package/runtime/api-3d/transforms.js +161 -0
  20. package/runtime/api-3d.js +154 -0
  21. package/runtime/api-effects.js +753 -0
  22. package/runtime/api-presets.js +85 -0
  23. package/runtime/api-skybox.js +178 -0
  24. package/runtime/api-sprites.js +100 -0
  25. package/runtime/api-voxel.js +601 -0
  26. package/runtime/api.js +201 -0
  27. package/runtime/assets.js +27 -0
  28. package/runtime/audio.js +114 -0
  29. package/runtime/collision.js +47 -0
  30. package/runtime/console.js +101 -0
  31. package/runtime/editor.js +233 -0
  32. package/runtime/font.js +233 -0
  33. package/runtime/framebuffer.js +28 -0
  34. package/runtime/fullscreen-button.js +185 -0
  35. package/runtime/gpu-canvas2d.js +47 -0
  36. package/runtime/gpu-threejs.js +639 -0
  37. package/runtime/gpu-webgl2.js +310 -0
  38. package/runtime/index.js +22 -0
  39. package/runtime/input.js +225 -0
  40. package/runtime/logger.js +60 -0
  41. package/runtime/physics.js +101 -0
  42. package/runtime/screens.js +213 -0
  43. package/runtime/storage.js +38 -0
  44. package/runtime/store.js +151 -0
  45. package/runtime/textinput.js +68 -0
  46. package/runtime/ui/buttons.js +124 -0
  47. package/runtime/ui/panels.js +105 -0
  48. package/runtime/ui/text.js +86 -0
  49. package/runtime/ui/widgets.js +141 -0
  50. package/runtime/ui.js +111 -0
  51. package/src/main.js +474 -0
  52. package/vite.config.js +63 -0
@@ -0,0 +1,85 @@
1
+ // runtime/api-presets.js
2
+ // One-call visual style presets for Nova64 — no new engine code required,
3
+ // each function is a curated combination of existing effects API calls.
4
+
5
+ export function presetsApi(gpu) {
6
+ // Internal: apply flat shading to every mesh currently in the scene
7
+ function _flatShadeMeshes() {
8
+ if (!gpu || !gpu.scene) return;
9
+ gpu.scene.traverse(obj => {
10
+ if (obj.isMesh && obj.material) {
11
+ obj.material.flatShading = true;
12
+ obj.material.needsUpdate = true;
13
+ }
14
+ });
15
+ }
16
+
17
+ function _smoothShadeMeshes() {
18
+ if (!gpu || !gpu.scene) return;
19
+ gpu.scene.traverse(obj => {
20
+ if (obj.isMesh && obj.material) {
21
+ obj.material.flatShading = false;
22
+ obj.material.needsUpdate = true;
23
+ }
24
+ });
25
+ }
26
+
27
+ /**
28
+ * Nintendo 64 aesthetic: no bloom, crisp FXAA, flat vignette edge,
29
+ * and flat shading on all scene meshes.
30
+ */
31
+ function enableN64Mode() {
32
+ const g = globalThis;
33
+ if (typeof g.disableBloom === 'function') g.disableBloom();
34
+ if (typeof g.enableFXAA === 'function') g.enableFXAA();
35
+ if (typeof g.disableVignette === 'function') g.disableVignette();
36
+ if (typeof g.disableChromaticAberration === 'function') g.disableChromaticAberration();
37
+ _flatShadeMeshes();
38
+ }
39
+
40
+ /**
41
+ * PlayStation 1 aesthetic: soft bloom, aggressive vignette, chromatic
42
+ * aberration, and flat shading (matches the PSX dithered look).
43
+ */
44
+ function enablePSXMode() {
45
+ const g = globalThis;
46
+ if (typeof g.enableBloom === 'function') g.enableBloom(0.8, 0.6, 0.4);
47
+ if (typeof g.enableVignette === 'function') g.enableVignette(2.0, 0.75);
48
+ if (typeof g.enableChromaticAberration === 'function') g.enableChromaticAberration();
49
+ if (typeof g.enableFXAA === 'function') g.enableFXAA();
50
+ _flatShadeMeshes();
51
+ }
52
+
53
+ /**
54
+ * Low-poly / indie style: flat-shaded meshes, subtle bloom highlight, light
55
+ * vignette, no chromatic aberration.
56
+ */
57
+ function enableLowPolyMode() {
58
+ const g = globalThis;
59
+ if (typeof g.disableChromaticAberration === 'function') g.disableChromaticAberration();
60
+ if (typeof g.enableBloom === 'function') g.enableBloom(0.4, 0.3, 0.7);
61
+ if (typeof g.enableVignette === 'function') g.enableVignette(0.8, 0.95);
62
+ if (typeof g.enableFXAA === 'function') g.enableFXAA();
63
+ _flatShadeMeshes();
64
+ }
65
+
66
+ /** Restore default smooth shading and disable visual presets. */
67
+ function disablePresetMode() {
68
+ const g = globalThis;
69
+ if (typeof g.disableBloom === 'function') g.disableBloom();
70
+ if (typeof g.disableVignette === 'function') g.disableVignette();
71
+ if (typeof g.disableChromaticAberration === 'function') g.disableChromaticAberration();
72
+ _smoothShadeMeshes();
73
+ }
74
+
75
+ return {
76
+ exposeTo(target) {
77
+ Object.assign(target, {
78
+ enableN64Mode,
79
+ enablePSXMode,
80
+ enableLowPolyMode,
81
+ disablePresetMode,
82
+ });
83
+ },
84
+ };
85
+ }
@@ -0,0 +1,178 @@
1
+ // Skybox API for Nova64 - Space, gradient, and solid sky backgrounds
2
+ import * as THREE from 'three';
3
+
4
+ export function skyboxApi(gpu) {
5
+ let skyboxMesh = null;
6
+ let starField = null;
7
+ let _rotSpeed = 1.0; // multiplier for animateSkybox speed
8
+ let _auto = false; // enableSkyboxAutoAnimate flag
9
+
10
+ // ── Space skybox ────────────────────────────────────────────────────────────
11
+ /**
12
+ * Create a procedural space background with stars and optional nebula.
13
+ * @param {object} [options]
14
+ * @param {number} [options.starCount=1000]
15
+ * @param {number} [options.starSize=2]
16
+ * @param {boolean} [options.nebulae=true]
17
+ * @param {number} [options.nebulaColor=0x4422aa]
18
+ */
19
+ function createSpaceSkybox(options = {}) {
20
+ const { starCount = 1000, starSize = 2, nebulae = true, nebulaColor = 0x4422aa } = options;
21
+
22
+ _clearSky();
23
+
24
+ const starGeometry = new THREE.BufferGeometry();
25
+ const starPositions = [];
26
+ const starColors = [];
27
+
28
+ for (let i = 0; i < starCount; i++) {
29
+ const radius = 500 + Math.random() * 500;
30
+ const theta = Math.random() * Math.PI * 2;
31
+ const phi = Math.acos(2 * Math.random() - 1);
32
+ starPositions.push(
33
+ radius * Math.sin(phi) * Math.cos(theta),
34
+ radius * Math.sin(phi) * Math.sin(theta),
35
+ radius * Math.cos(phi)
36
+ );
37
+ const c = Math.random();
38
+ if (c < 0.7) starColors.push(1, 1, 1);
39
+ else if (c < 0.85) starColors.push(0.7, 0.8, 1);
40
+ else if (c < 0.95) starColors.push(1, 1, 0.7);
41
+ else starColors.push(1, 0.7, 0.6);
42
+ }
43
+
44
+ starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starPositions, 3));
45
+ starGeometry.setAttribute('color', new THREE.Float32BufferAttribute(starColors, 3));
46
+
47
+ starField = new THREE.Points(
48
+ starGeometry,
49
+ new THREE.PointsMaterial({
50
+ size: starSize,
51
+ vertexColors: true,
52
+ transparent: true,
53
+ opacity: 0.8,
54
+ sizeAttenuation: true,
55
+ })
56
+ );
57
+ gpu.scene.add(starField);
58
+
59
+ if (nebulae) {
60
+ skyboxMesh = _gradientSphere(0x000511, nebulaColor);
61
+ }
62
+ return { starField, skyboxMesh };
63
+ }
64
+
65
+ // ── Gradient skybox ─────────────────────────────────────────────────────────
66
+ /**
67
+ * Create a two-colour gradient sky (daylight, sunset, alien worlds, etc.).
68
+ * @param {number} [topColor=0x1a6aa8] - hex colour at the zenith
69
+ * @param {number} [bottomColor=0xf48c60] - hex colour at the horizon
70
+ */
71
+ function createGradientSkybox(topColor = 0x1a6aa8, bottomColor = 0xf48c60) {
72
+ _clearSky();
73
+ skyboxMesh = _gradientSphere(topColor, bottomColor);
74
+ }
75
+
76
+ // ── Solid-colour skybox ──────────────────────────────────────────────────────
77
+ /**
78
+ * Fill the background with a single colour (indoor, cave, void scenes).
79
+ * @param {number} [color=0x000000]
80
+ */
81
+ function createSolidSkybox(color = 0x000000) {
82
+ _clearSky();
83
+ gpu.scene.background = new THREE.Color(color);
84
+ }
85
+
86
+ // ── Shared gradient-sphere helper ────────────────────────────────────────────
87
+ function _gradientSphere(topColor, bottomColor) {
88
+ const geo = new THREE.SphereGeometry(800, 32, 32);
89
+ const mat = new THREE.ShaderMaterial({
90
+ uniforms: {
91
+ topColor: { value: new THREE.Color(topColor) },
92
+ bottomColor: { value: new THREE.Color(bottomColor) },
93
+ },
94
+ vertexShader: `
95
+ varying vec3 vWorldPosition;
96
+ void main() {
97
+ vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
98
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
99
+ }`,
100
+ fragmentShader: `
101
+ uniform vec3 topColor;
102
+ uniform vec3 bottomColor;
103
+ varying vec3 vWorldPosition;
104
+ void main() {
105
+ float h = normalize(vWorldPosition).y;
106
+ gl_FragColor = vec4(mix(bottomColor, topColor, max(h * 0.5 + 0.5, 0.0)), 1.0);
107
+ }`,
108
+ side: THREE.BackSide,
109
+ depthWrite: false,
110
+ });
111
+ const mesh = new THREE.Mesh(geo, mat);
112
+ gpu.scene.add(mesh);
113
+ return mesh;
114
+ }
115
+
116
+ function _clearSky() {
117
+ if (skyboxMesh) {
118
+ gpu.scene.remove(skyboxMesh);
119
+ skyboxMesh.geometry?.dispose();
120
+ skyboxMesh.material?.dispose();
121
+ skyboxMesh = null;
122
+ }
123
+ if (starField) {
124
+ gpu.scene.remove(starField);
125
+ starField.geometry?.dispose();
126
+ starField.material?.dispose();
127
+ starField = null;
128
+ }
129
+ if (gpu.scene.background instanceof THREE.Color) {
130
+ gpu.scene.background = null;
131
+ }
132
+ }
133
+
134
+ // ── Animation controls ───────────────────────────────────────────────────────
135
+ /** Rotate the star-field one frame. Call in update(dt). */
136
+ function animateSkybox(dt) {
137
+ if (starField) starField.rotation.y += dt * 0.01 * _rotSpeed;
138
+ }
139
+
140
+ /** Control star rotation speed (0 = frozen, 1 = default, -1 = reverse). */
141
+ function setSkyboxSpeed(multiplier) {
142
+ _rotSpeed = multiplier;
143
+ }
144
+
145
+ /** Auto-animate skybox in the engine loop — no need to call animateSkybox manually. */
146
+ function enableSkyboxAutoAnimate(speed = 1) {
147
+ _auto = true;
148
+ _rotSpeed = speed;
149
+ }
150
+ function disableSkyboxAutoAnimate() {
151
+ _auto = false;
152
+ }
153
+
154
+ function clearSkybox() {
155
+ _clearSky();
156
+ }
157
+
158
+ // Internal: called by src/main.js every frame
159
+ function _tick(dt) {
160
+ if (_auto) animateSkybox(dt);
161
+ }
162
+
163
+ return {
164
+ _tick,
165
+ exposeTo(target) {
166
+ Object.assign(target, {
167
+ createSpaceSkybox,
168
+ createGradientSkybox,
169
+ createSolidSkybox,
170
+ animateSkybox,
171
+ setSkyboxSpeed,
172
+ enableSkyboxAutoAnimate,
173
+ disableSkyboxAutoAnimate,
174
+ clearSkybox,
175
+ });
176
+ },
177
+ };
178
+ }
@@ -0,0 +1,100 @@
1
+ // runtime/api-sprites.js
2
+ import { loadSpriteSheet, loadTilemap, loadImageElement } from './assets.js';
3
+
4
+ export function spriteApi(gpu) {
5
+ const assets = { sheet: null, map: null, tileSize: 8 };
6
+ let camRef = { x: 0, y: 0 };
7
+
8
+ // Reserved for future camera-relative sprite rendering
9
+ // function _setCameraRef(ref) { camRef = ref; }
10
+ function getSpriteSheetImage() {
11
+ return assets.sheet?.image || null;
12
+ }
13
+
14
+ async function loadSprites(url, tileSize = 8) {
15
+ assets.sheet = await loadSpriteSheet(url, tileSize);
16
+ assets.tileSize = tileSize;
17
+ if (gpu.updateTextureForImage) gpu.updateTextureForImage(assets.sheet.image);
18
+ }
19
+ async function loadMap(url) {
20
+ assets.map = await loadTilemap(url);
21
+ globalThis.__nova_map = assets.map;
22
+ }
23
+
24
+ async function applySpriteSheetDataURL(dataURL) {
25
+ const img = await loadImageElement(dataURL);
26
+ if (!assets.sheet)
27
+ assets.sheet = {
28
+ image: img,
29
+ sheetWidth: img.naturalWidth,
30
+ tileSize: 8,
31
+ cols: Math.floor(img.naturalWidth / 8),
32
+ };
33
+ else {
34
+ assets.sheet.image = img;
35
+ assets.sheet.sheetWidth = img.naturalWidth;
36
+ assets.sheet.cols = Math.floor(img.naturalWidth / assets.tileSize);
37
+ }
38
+ if (gpu.updateTextureForImage) gpu.updateTextureForImage(img);
39
+ }
40
+
41
+ function spr(
42
+ id,
43
+ x,
44
+ y,
45
+ { flipX: _flipX = false, flipY: _flipY = false, scale = 1, parallax = 1 } = {}
46
+ ) {
47
+ const ts = assets.tileSize;
48
+ if (!assets.sheet) return;
49
+ const cols = Math.floor(assets.sheet.sheetWidth / ts);
50
+ const sx0 = (id % cols) * ts;
51
+ const sy0 = Math.floor(id / cols) * ts;
52
+ // camera
53
+ const camX = Math.floor(camRef.x * parallax);
54
+ const camY = Math.floor(camRef.y * parallax);
55
+ const dx = (x | 0) - camX;
56
+ const dy = (y | 0) - camY;
57
+
58
+ if (gpu.supportsSpriteBatch && gpu.supportsSpriteBatch()) {
59
+ gpu.queueSprite(assets.sheet.image, sx0, sy0, ts, ts, dx, dy, scale);
60
+ return;
61
+ }
62
+ }
63
+
64
+ function mapDraw(mx, my, w, h, dx, dy, { scale = 1, parallax = 1 } = {}) {
65
+ if (!assets.map) return;
66
+ const ts = assets.tileSize;
67
+ const { width, height, data } = assets.map;
68
+ const camX = Math.floor(camRef.x * parallax);
69
+ const camY = Math.floor(camRef.y * parallax);
70
+ const baseX = dx - camX;
71
+ const baseY = dy - camY;
72
+ for (let ty = 0; ty < h; ty++) {
73
+ for (let tx = 0; tx < w; tx++) {
74
+ const gx = mx + tx;
75
+ const gy = my + ty;
76
+ if (gx < 0 || gy < 0 || gx >= width || gy >= height) continue;
77
+ const id = data[gy * width + gx];
78
+ spr(id, baseX + tx * ts * scale, baseY + ty * ts * scale, { scale, parallax });
79
+ }
80
+ }
81
+ }
82
+
83
+ return {
84
+ exposeTo(target) {
85
+ Object.assign(target, {
86
+ spr,
87
+ mapDraw,
88
+ loadSprites,
89
+ loadMap,
90
+ getSpriteSheetImage,
91
+ applySpriteSheetDataURL,
92
+ });
93
+ },
94
+ setCameraRef(ref) {
95
+ camRef = ref;
96
+ },
97
+ getSpriteSheetImage,
98
+ applySpriteSheetDataURL,
99
+ };
100
+ }