nova64 0.2.1 → 0.2.3
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/package.json +13 -2
- package/runtime/api-3d/particles.js +296 -0
- package/runtime/api-3d.js +11 -0
- package/runtime/index.d.ts +682 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nova64",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Nova64 — Ultimate 3D Fantasy Console runtime for JavaScript games powered by Three.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fantasy-console",
|
|
@@ -22,8 +22,12 @@
|
|
|
22
22
|
},
|
|
23
23
|
"type": "module",
|
|
24
24
|
"main": "./runtime/index.js",
|
|
25
|
+
"types": "./runtime/index.d.ts",
|
|
25
26
|
"exports": {
|
|
26
|
-
".":
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./runtime/index.d.ts",
|
|
29
|
+
"default": "./runtime/index.js"
|
|
30
|
+
},
|
|
27
31
|
"./runtime/*": "./runtime/*.js",
|
|
28
32
|
"./runtime/api-3d/*": "./runtime/api-3d/*.js",
|
|
29
33
|
"./runtime/ui/*": "./runtime/ui/*.js"
|
|
@@ -208,6 +212,13 @@
|
|
|
208
212
|
"setInstanceColor": "readonly",
|
|
209
213
|
"finalizeInstances": "readonly",
|
|
210
214
|
"removeInstancedMesh": "readonly",
|
|
215
|
+
"createParticleSystem": "readonly",
|
|
216
|
+
"setParticleEmitter": "readonly",
|
|
217
|
+
"emitParticle": "readonly",
|
|
218
|
+
"burstParticles": "readonly",
|
|
219
|
+
"updateParticles": "readonly",
|
|
220
|
+
"removeParticleSystem": "readonly",
|
|
221
|
+
"getParticleStats": "readonly",
|
|
211
222
|
"createLODMesh": "readonly",
|
|
212
223
|
"setLODPosition": "readonly",
|
|
213
224
|
"removeLODMesh": "readonly",
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// runtime/api-3d/particles.js
|
|
2
|
+
// GPU particle system: typed-array physics simulation, single InstancedMesh draw call
|
|
3
|
+
//
|
|
4
|
+
// API:
|
|
5
|
+
// createParticleSystem(maxParticles, options) → systemId
|
|
6
|
+
// setParticleEmitter(systemId, emitter) configure emission
|
|
7
|
+
// emitParticle(systemId, overrides?) fire one particle
|
|
8
|
+
// burstParticles(systemId, count, overrides?) fire N particles at once
|
|
9
|
+
// updateParticles(dt) step all systems (call each frame)
|
|
10
|
+
// removeParticleSystem(systemId) cleanup
|
|
11
|
+
|
|
12
|
+
import * as THREE from 'three';
|
|
13
|
+
|
|
14
|
+
export function particlesModule({ scene, counters }) {
|
|
15
|
+
// Per-particle typed arrays layout (indices into Float32Array pools):
|
|
16
|
+
// px py pz — position
|
|
17
|
+
// vx vy vz — velocity
|
|
18
|
+
// age life — lifetime tracking
|
|
19
|
+
// r g b — color (0-1)
|
|
20
|
+
// size — scale
|
|
21
|
+
// active — 1 = alive, 0 = dead
|
|
22
|
+
|
|
23
|
+
const STRIDE = 13; // slots per particle
|
|
24
|
+
|
|
25
|
+
const particleSystems = new Map();
|
|
26
|
+
let psCounter = 0;
|
|
27
|
+
|
|
28
|
+
const _dummy = new THREE.Object3D();
|
|
29
|
+
const _color = new THREE.Color();
|
|
30
|
+
|
|
31
|
+
function createParticleSystem(maxParticles = 200, options = {}) {
|
|
32
|
+
const {
|
|
33
|
+
shape = 'sphere',
|
|
34
|
+
size = 0.15,
|
|
35
|
+
segments = 4,
|
|
36
|
+
color = 0xffaa00,
|
|
37
|
+
emissive = 0xff6600,
|
|
38
|
+
emissiveIntensity = 2.0,
|
|
39
|
+
gravity = -9.8,
|
|
40
|
+
drag = 0.95,
|
|
41
|
+
// Emitter defaults
|
|
42
|
+
emitterX = 0,
|
|
43
|
+
emitterY = 0,
|
|
44
|
+
emitterZ = 0,
|
|
45
|
+
emitRate = 20, // particles per second
|
|
46
|
+
minLife = 0.8,
|
|
47
|
+
maxLife = 2.0,
|
|
48
|
+
minSpeed = 2,
|
|
49
|
+
maxSpeed = 8,
|
|
50
|
+
spread = Math.PI, // half-angle cone spread (PI = hemisphere)
|
|
51
|
+
minSize = 0.05,
|
|
52
|
+
maxSize = 0.3,
|
|
53
|
+
startColor = color,
|
|
54
|
+
endColor = 0x000000,
|
|
55
|
+
} = options;
|
|
56
|
+
|
|
57
|
+
// Geometry
|
|
58
|
+
let geometry;
|
|
59
|
+
if (shape === 'cube') {
|
|
60
|
+
geometry = new THREE.BoxGeometry(size, size, size);
|
|
61
|
+
} else {
|
|
62
|
+
geometry = new THREE.SphereGeometry(size, segments, segments);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const material = new THREE.MeshBasicMaterial({ color, vertexColors: false });
|
|
66
|
+
material.emissive = new THREE.Color(emissive);
|
|
67
|
+
// MeshBasicMaterial doesn't have emissive — use MeshStandardMaterial instead
|
|
68
|
+
const stdMat = new THREE.MeshStandardMaterial({
|
|
69
|
+
color,
|
|
70
|
+
emissive: new THREE.Color(emissive),
|
|
71
|
+
emissiveIntensity,
|
|
72
|
+
roughness: 0.8,
|
|
73
|
+
metalness: 0.0,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const mesh = new THREE.InstancedMesh(geometry, stdMat, maxParticles);
|
|
77
|
+
mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
78
|
+
mesh.castShadow = false;
|
|
79
|
+
mesh.receiveShadow = false;
|
|
80
|
+
|
|
81
|
+
// Hide all instances initially by scaling to zero
|
|
82
|
+
_dummy.position.set(0, -9999, 0);
|
|
83
|
+
_dummy.scale.set(0, 0, 0);
|
|
84
|
+
_dummy.updateMatrix();
|
|
85
|
+
for (let i = 0; i < maxParticles; i++) {
|
|
86
|
+
mesh.setMatrixAt(i, _dummy.matrix);
|
|
87
|
+
}
|
|
88
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
89
|
+
|
|
90
|
+
// Enable per-instance color
|
|
91
|
+
mesh.instanceColor = new THREE.InstancedBufferAttribute(new Float32Array(maxParticles * 3), 3);
|
|
92
|
+
|
|
93
|
+
scene.add(mesh);
|
|
94
|
+
|
|
95
|
+
// Typed-array particle state pool
|
|
96
|
+
const pool = new Float32Array(maxParticles * STRIDE);
|
|
97
|
+
// All start inactive (age = life = 0, active slot = 0)
|
|
98
|
+
|
|
99
|
+
const id = ++psCounter;
|
|
100
|
+
particleSystems.set(id, {
|
|
101
|
+
mesh,
|
|
102
|
+
pool,
|
|
103
|
+
maxParticles,
|
|
104
|
+
freeList: Array.from({ length: maxParticles }, (_, i) => i),
|
|
105
|
+
activeCount: 0,
|
|
106
|
+
emitAccum: 0,
|
|
107
|
+
emitter: {
|
|
108
|
+
x: emitterX,
|
|
109
|
+
y: emitterY,
|
|
110
|
+
z: emitterZ,
|
|
111
|
+
emitRate,
|
|
112
|
+
minLife,
|
|
113
|
+
maxLife,
|
|
114
|
+
minSpeed,
|
|
115
|
+
maxSpeed,
|
|
116
|
+
spread,
|
|
117
|
+
minSize,
|
|
118
|
+
maxSize,
|
|
119
|
+
},
|
|
120
|
+
config: {
|
|
121
|
+
gravity,
|
|
122
|
+
drag,
|
|
123
|
+
startColor: new THREE.Color(startColor),
|
|
124
|
+
endColor: new THREE.Color(endColor),
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
counters.particle = (counters.particle || 0) + 1;
|
|
129
|
+
return id;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function setParticleEmitter(systemId, emitter = {}) {
|
|
133
|
+
const sys = particleSystems.get(systemId);
|
|
134
|
+
if (!sys) return;
|
|
135
|
+
Object.assign(sys.emitter, emitter);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function _spawnParticle(sys, overrides = {}) {
|
|
139
|
+
if (sys.freeList.length === 0) return; // pool full
|
|
140
|
+
const idx = sys.freeList.pop();
|
|
141
|
+
const base = idx * STRIDE;
|
|
142
|
+
const { pool, emitter } = sys;
|
|
143
|
+
|
|
144
|
+
const ex = overrides.x ?? emitter.x;
|
|
145
|
+
const ey = overrides.y ?? emitter.y;
|
|
146
|
+
const ez = overrides.z ?? emitter.z;
|
|
147
|
+
|
|
148
|
+
// Random direction within spread cone (pointing up by default)
|
|
149
|
+
const phi = Math.random() * Math.PI * 2;
|
|
150
|
+
const theta = Math.random() * (overrides.spread ?? emitter.spread);
|
|
151
|
+
const ct = Math.cos(theta);
|
|
152
|
+
const st = Math.sin(theta);
|
|
153
|
+
const speed = emitter.minSpeed + Math.random() * (emitter.maxSpeed - emitter.minSpeed);
|
|
154
|
+
const vx = overrides.vx ?? st * Math.cos(phi) * speed;
|
|
155
|
+
const vy = overrides.vy ?? ct * speed;
|
|
156
|
+
const vz = overrides.vz ?? st * Math.sin(phi) * speed;
|
|
157
|
+
|
|
158
|
+
const life = emitter.minLife + Math.random() * (emitter.maxLife - emitter.minLife);
|
|
159
|
+
const sz = emitter.minSize + Math.random() * (emitter.maxSize - emitter.minSize);
|
|
160
|
+
|
|
161
|
+
// position
|
|
162
|
+
pool[base + 0] = ex;
|
|
163
|
+
pool[base + 1] = ey;
|
|
164
|
+
pool[base + 2] = ez;
|
|
165
|
+
// velocity
|
|
166
|
+
pool[base + 3] = vx;
|
|
167
|
+
pool[base + 4] = vy;
|
|
168
|
+
pool[base + 5] = vz;
|
|
169
|
+
// age, life
|
|
170
|
+
pool[base + 6] = 0;
|
|
171
|
+
pool[base + 7] = life > 0 ? life : 1;
|
|
172
|
+
// color (start)
|
|
173
|
+
const sc = sys.config.startColor;
|
|
174
|
+
pool[base + 8] = overrides.r ?? sc.r;
|
|
175
|
+
pool[base + 9] = overrides.g ?? sc.g;
|
|
176
|
+
pool[base + 10] = overrides.b ?? sc.b;
|
|
177
|
+
// size
|
|
178
|
+
pool[base + 11] = sz;
|
|
179
|
+
// active
|
|
180
|
+
pool[base + 12] = 1;
|
|
181
|
+
|
|
182
|
+
sys.activeCount++;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function emitParticle(systemId, overrides = {}) {
|
|
186
|
+
const sys = particleSystems.get(systemId);
|
|
187
|
+
if (sys) _spawnParticle(sys, overrides);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function burstParticles(systemId, count = 10, overrides = {}) {
|
|
191
|
+
const sys = particleSystems.get(systemId);
|
|
192
|
+
if (!sys) return;
|
|
193
|
+
for (let i = 0; i < count; i++) _spawnParticle(sys, overrides);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function updateParticles(dt) {
|
|
197
|
+
particleSystems.forEach(sys => {
|
|
198
|
+
const { pool, maxParticles, mesh, config, emitter } = sys;
|
|
199
|
+
|
|
200
|
+
// Auto-emit based on rate
|
|
201
|
+
sys.emitAccum += emitter.emitRate * dt;
|
|
202
|
+
while (sys.emitAccum >= 1 && sys.freeList.length > 0) {
|
|
203
|
+
_spawnParticle(sys);
|
|
204
|
+
sys.emitAccum -= 1;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let needsUpdate = false;
|
|
208
|
+
|
|
209
|
+
for (let i = 0; i < maxParticles; i++) {
|
|
210
|
+
const base = i * STRIDE;
|
|
211
|
+
if (pool[base + 12] === 0) continue; // inactive
|
|
212
|
+
|
|
213
|
+
// Step age
|
|
214
|
+
pool[base + 6] += dt;
|
|
215
|
+
const age = pool[base + 6];
|
|
216
|
+
const life = pool[base + 7];
|
|
217
|
+
|
|
218
|
+
if (age >= life) {
|
|
219
|
+
// Kill particle
|
|
220
|
+
pool[base + 12] = 0;
|
|
221
|
+
sys.freeList.push(i);
|
|
222
|
+
sys.activeCount--;
|
|
223
|
+
|
|
224
|
+
// Scale to zero
|
|
225
|
+
_dummy.position.set(0, -9999, 0);
|
|
226
|
+
_dummy.scale.set(0, 0, 0);
|
|
227
|
+
_dummy.updateMatrix();
|
|
228
|
+
mesh.setMatrixAt(i, _dummy.matrix);
|
|
229
|
+
needsUpdate = true;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Physics integration
|
|
234
|
+
pool[base + 3] *= config.drag; // drag on vx
|
|
235
|
+
pool[base + 5] *= config.drag; // drag on vz
|
|
236
|
+
pool[base + 4] += config.gravity * dt; // gravity on vy
|
|
237
|
+
|
|
238
|
+
pool[base + 0] += pool[base + 3] * dt; // px
|
|
239
|
+
pool[base + 1] += pool[base + 4] * dt; // py
|
|
240
|
+
pool[base + 2] += pool[base + 5] * dt; // pz
|
|
241
|
+
|
|
242
|
+
// Interpolate color start→end
|
|
243
|
+
const t = age / life;
|
|
244
|
+
const r = pool[base + 8] * (1 - t) + config.endColor.r * t;
|
|
245
|
+
const g = pool[base + 9] * (1 - t) + config.endColor.g * t;
|
|
246
|
+
const b = pool[base + 10] * (1 - t) + config.endColor.b * t;
|
|
247
|
+
_color.setRGB(r, g, b);
|
|
248
|
+
mesh.setColorAt(i, _color);
|
|
249
|
+
|
|
250
|
+
// Shrink as particle ages
|
|
251
|
+
const sz = pool[base + 11] * (1 - t * 0.8);
|
|
252
|
+
|
|
253
|
+
_dummy.position.set(pool[base + 0], pool[base + 1], pool[base + 2]);
|
|
254
|
+
_dummy.scale.set(sz, sz, sz);
|
|
255
|
+
_dummy.updateMatrix();
|
|
256
|
+
mesh.setMatrixAt(i, _dummy.matrix);
|
|
257
|
+
needsUpdate = true;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (needsUpdate) {
|
|
261
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
262
|
+
if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function removeParticleSystem(systemId) {
|
|
268
|
+
const sys = particleSystems.get(systemId);
|
|
269
|
+
if (!sys) return false;
|
|
270
|
+
scene.remove(sys.mesh);
|
|
271
|
+
sys.mesh.geometry?.dispose();
|
|
272
|
+
sys.mesh.material?.dispose();
|
|
273
|
+
particleSystems.delete(systemId);
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function getParticleStats(systemId) {
|
|
278
|
+
const sys = particleSystems.get(systemId);
|
|
279
|
+
if (!sys) return null;
|
|
280
|
+
return {
|
|
281
|
+
active: sys.activeCount,
|
|
282
|
+
max: sys.maxParticles,
|
|
283
|
+
free: sys.freeList.length,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
createParticleSystem,
|
|
289
|
+
setParticleEmitter,
|
|
290
|
+
emitParticle,
|
|
291
|
+
burstParticles,
|
|
292
|
+
updateParticles,
|
|
293
|
+
removeParticleSystem,
|
|
294
|
+
getParticleStats,
|
|
295
|
+
};
|
|
296
|
+
}
|
package/runtime/api-3d.js
CHANGED
|
@@ -11,6 +11,7 @@ import { modelsModule } from './api-3d/models.js';
|
|
|
11
11
|
import { instancingModule } from './api-3d/instancing.js';
|
|
12
12
|
import { pbrModule } from './api-3d/pbr.js';
|
|
13
13
|
import { sceneModule } from './api-3d/scene.js';
|
|
14
|
+
import { particlesModule } from './api-3d/particles.js';
|
|
14
15
|
|
|
15
16
|
export function threeDApi(gpu) {
|
|
16
17
|
if (!gpu.getScene) return { exposeTo: () => {} };
|
|
@@ -53,6 +54,7 @@ export function threeDApi(gpu) {
|
|
|
53
54
|
Object.assign(ctx, modelsModule(ctx));
|
|
54
55
|
Object.assign(ctx, instancingModule(ctx));
|
|
55
56
|
Object.assign(ctx, pbrModule(ctx));
|
|
57
|
+
Object.assign(ctx, particlesModule(ctx));
|
|
56
58
|
Object.assign(ctx, sceneModule(ctx)); // last: uses late binding to call other modules
|
|
57
59
|
|
|
58
60
|
return {
|
|
@@ -138,6 +140,15 @@ export function threeDApi(gpu) {
|
|
|
138
140
|
setNormalMap: ctx.setNormalMap,
|
|
139
141
|
setPBRMaps: ctx.setPBRMaps,
|
|
140
142
|
|
|
143
|
+
// GPU particle system
|
|
144
|
+
createParticleSystem: ctx.createParticleSystem,
|
|
145
|
+
setParticleEmitter: ctx.setParticleEmitter,
|
|
146
|
+
emitParticle: ctx.emitParticle,
|
|
147
|
+
burstParticles: ctx.burstParticles,
|
|
148
|
+
updateParticles: ctx.updateParticles,
|
|
149
|
+
removeParticleSystem: ctx.removeParticleSystem,
|
|
150
|
+
getParticleStats: ctx.getParticleStats,
|
|
151
|
+
|
|
141
152
|
// Interaction / stats / convenience
|
|
142
153
|
raycastFromCamera: ctx.raycastFromCamera,
|
|
143
154
|
get3DStats: ctx.get3DStats,
|
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
// Nova64 — Type declarations
|
|
2
|
+
// https://github.com/seacloud9/nova64
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Shared primitives
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
/** Hex colour integer, e.g. 0xff0000 for red. */
|
|
9
|
+
export type Color = number;
|
|
10
|
+
|
|
11
|
+
/** Mesh identifier returned by primitive-creation functions. */
|
|
12
|
+
export type MeshId = number;
|
|
13
|
+
|
|
14
|
+
/** Light identifier returned by createPointLight. */
|
|
15
|
+
export type LightId = number;
|
|
16
|
+
|
|
17
|
+
/** Instanced-mesh identifier returned by createInstancedMesh. */
|
|
18
|
+
export type InstancedMeshId = number;
|
|
19
|
+
|
|
20
|
+
/** LOD identifier returned by createLODMesh. */
|
|
21
|
+
export type LODId = number;
|
|
22
|
+
|
|
23
|
+
/** Particle system identifier returned by createParticleSystem. */
|
|
24
|
+
export type ParticleSystemId = number;
|
|
25
|
+
|
|
26
|
+
export interface ParticleSystemOptions {
|
|
27
|
+
shape?: 'sphere' | 'cube';
|
|
28
|
+
size?: number;
|
|
29
|
+
segments?: number;
|
|
30
|
+
color?: Color;
|
|
31
|
+
emissive?: Color;
|
|
32
|
+
emissiveIntensity?: number;
|
|
33
|
+
gravity?: number;
|
|
34
|
+
drag?: number;
|
|
35
|
+
emitterX?: number;
|
|
36
|
+
emitterY?: number;
|
|
37
|
+
emitterZ?: number;
|
|
38
|
+
emitRate?: number;
|
|
39
|
+
minLife?: number;
|
|
40
|
+
maxLife?: number;
|
|
41
|
+
minSpeed?: number;
|
|
42
|
+
maxSpeed?: number;
|
|
43
|
+
spread?: number;
|
|
44
|
+
minSize?: number;
|
|
45
|
+
maxSize?: number;
|
|
46
|
+
startColor?: Color;
|
|
47
|
+
endColor?: Color;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ParticleEmitter {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
z: number;
|
|
54
|
+
emitRate: number;
|
|
55
|
+
minLife: number;
|
|
56
|
+
maxLife: number;
|
|
57
|
+
minSpeed: number;
|
|
58
|
+
maxSpeed: number;
|
|
59
|
+
spread: number;
|
|
60
|
+
minSize: number;
|
|
61
|
+
maxSize: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ParticleOverrides {
|
|
65
|
+
x: number;
|
|
66
|
+
y: number;
|
|
67
|
+
z: number;
|
|
68
|
+
vx: number;
|
|
69
|
+
vy: number;
|
|
70
|
+
vz: number;
|
|
71
|
+
spread: number;
|
|
72
|
+
r: number;
|
|
73
|
+
g: number;
|
|
74
|
+
b: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Panel object returned by createPanel. */
|
|
78
|
+
export interface Panel {
|
|
79
|
+
x: number;
|
|
80
|
+
y: number;
|
|
81
|
+
width: number;
|
|
82
|
+
height: number;
|
|
83
|
+
options: PanelOptions;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Button object returned by createButton. */
|
|
87
|
+
export interface Button {
|
|
88
|
+
x: number;
|
|
89
|
+
y: number;
|
|
90
|
+
width: number;
|
|
91
|
+
height: number;
|
|
92
|
+
text: string;
|
|
93
|
+
callback: () => void;
|
|
94
|
+
options: ButtonOptions;
|
|
95
|
+
hovered: boolean;
|
|
96
|
+
pressed: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface MousePosition {
|
|
100
|
+
x: number;
|
|
101
|
+
y: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Material / primitive options
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
export interface MeshOptions {
|
|
109
|
+
/** @default 'standard' */
|
|
110
|
+
material?: 'standard' | 'holographic' | 'metallic' | 'emissive' | 'wireframe';
|
|
111
|
+
roughness?: number;
|
|
112
|
+
metalness?: number;
|
|
113
|
+
emissive?: Color;
|
|
114
|
+
emissiveIntensity?: number;
|
|
115
|
+
transparent?: boolean;
|
|
116
|
+
opacity?: number;
|
|
117
|
+
wireframe?: boolean;
|
|
118
|
+
flatShading?: boolean;
|
|
119
|
+
segments?: number;
|
|
120
|
+
size?: number;
|
|
121
|
+
height?: number;
|
|
122
|
+
width?: number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface LODLevel {
|
|
126
|
+
shape?: 'cube' | 'sphere' | 'plane' | 'cylinder' | 'cone';
|
|
127
|
+
size?: number;
|
|
128
|
+
color?: Color;
|
|
129
|
+
distance: number;
|
|
130
|
+
options?: MeshOptions;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface PBRMaps {
|
|
134
|
+
normalMap?: THREE.Texture | null;
|
|
135
|
+
roughnessMap?: THREE.Texture | null;
|
|
136
|
+
metalnessMap?: THREE.Texture | null;
|
|
137
|
+
aoMap?: THREE.Texture | null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// UI options
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
export interface PanelOptions {
|
|
145
|
+
color?: Color;
|
|
146
|
+
border?: Color;
|
|
147
|
+
borderWidth?: number;
|
|
148
|
+
alpha?: number;
|
|
149
|
+
radius?: number;
|
|
150
|
+
title?: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface ButtonOptions {
|
|
154
|
+
normalColor?: Color;
|
|
155
|
+
hoverColor?: Color;
|
|
156
|
+
pressedColor?: Color;
|
|
157
|
+
textColor?: Color;
|
|
158
|
+
borderColor?: Color;
|
|
159
|
+
borderWidth?: number;
|
|
160
|
+
radius?: number;
|
|
161
|
+
fontSize?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface ProgressBarOptions {
|
|
165
|
+
backgroundColor?: Color;
|
|
166
|
+
fillColor?: Color;
|
|
167
|
+
borderColor?: Color;
|
|
168
|
+
showText?: boolean;
|
|
169
|
+
textColor?: Color;
|
|
170
|
+
radius?: number;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Stats
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
export interface Stats3D {
|
|
178
|
+
meshCount: number;
|
|
179
|
+
lightCount: number;
|
|
180
|
+
instancedMeshCount: number;
|
|
181
|
+
lodCount: number;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Logger
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
export interface LogRecord {
|
|
189
|
+
level: number;
|
|
190
|
+
message: string;
|
|
191
|
+
args: unknown[];
|
|
192
|
+
timestamp: number;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export declare const LogLevel: Readonly<{
|
|
196
|
+
DEBUG: 0;
|
|
197
|
+
INFO: 1;
|
|
198
|
+
WARN: 2;
|
|
199
|
+
ERROR: 3;
|
|
200
|
+
NONE: 4;
|
|
201
|
+
}>;
|
|
202
|
+
|
|
203
|
+
export declare class Logger {
|
|
204
|
+
level: number;
|
|
205
|
+
history: LogRecord[];
|
|
206
|
+
debug(message: string, ...args: unknown[]): void;
|
|
207
|
+
info(message: string, ...args: unknown[]): void;
|
|
208
|
+
warn(message: string, ...args: unknown[]): void;
|
|
209
|
+
error(message: string, ...args: unknown[]): void;
|
|
210
|
+
setLevel(level: number): void;
|
|
211
|
+
getHistory(): LogRecord[];
|
|
212
|
+
clearHistory(): void;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export declare const logger: Logger;
|
|
216
|
+
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// 3D API
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
|
|
221
|
+
export interface ThreeDApiInstance {
|
|
222
|
+
// Primitives
|
|
223
|
+
createCube(
|
|
224
|
+
size?: number,
|
|
225
|
+
color?: Color,
|
|
226
|
+
position?: [number, number, number],
|
|
227
|
+
options?: MeshOptions
|
|
228
|
+
): MeshId;
|
|
229
|
+
createSphere(
|
|
230
|
+
radius?: number,
|
|
231
|
+
color?: Color,
|
|
232
|
+
position?: [number, number, number],
|
|
233
|
+
segments?: number,
|
|
234
|
+
options?: MeshOptions
|
|
235
|
+
): MeshId;
|
|
236
|
+
createCylinder(
|
|
237
|
+
radiusTop?: number,
|
|
238
|
+
radiusBottom?: number,
|
|
239
|
+
height?: number,
|
|
240
|
+
color?: Color,
|
|
241
|
+
position?: [number, number, number],
|
|
242
|
+
options?: MeshOptions
|
|
243
|
+
): MeshId;
|
|
244
|
+
createPlane(
|
|
245
|
+
width?: number,
|
|
246
|
+
height?: number,
|
|
247
|
+
color?: Color,
|
|
248
|
+
position?: [number, number, number]
|
|
249
|
+
): MeshId;
|
|
250
|
+
createAdvancedCube(
|
|
251
|
+
size?: number,
|
|
252
|
+
materialOptions?: MeshOptions,
|
|
253
|
+
position?: [number, number, number]
|
|
254
|
+
): MeshId;
|
|
255
|
+
createAdvancedSphere(
|
|
256
|
+
radius?: number,
|
|
257
|
+
materialOptions?: MeshOptions,
|
|
258
|
+
position?: [number, number, number]
|
|
259
|
+
): MeshId;
|
|
260
|
+
createTorus(
|
|
261
|
+
radius?: number,
|
|
262
|
+
tube?: number,
|
|
263
|
+
color?: Color,
|
|
264
|
+
position?: [number, number, number],
|
|
265
|
+
options?: MeshOptions
|
|
266
|
+
): MeshId;
|
|
267
|
+
createCone(
|
|
268
|
+
radius?: number,
|
|
269
|
+
height?: number,
|
|
270
|
+
color?: Color,
|
|
271
|
+
position?: [number, number, number],
|
|
272
|
+
options?: MeshOptions
|
|
273
|
+
): MeshId;
|
|
274
|
+
createCapsule(
|
|
275
|
+
radius?: number,
|
|
276
|
+
length?: number,
|
|
277
|
+
color?: Color,
|
|
278
|
+
position?: [number, number, number],
|
|
279
|
+
options?: MeshOptions
|
|
280
|
+
): MeshId;
|
|
281
|
+
|
|
282
|
+
// Mesh management
|
|
283
|
+
destroyMesh(id: MeshId): void;
|
|
284
|
+
removeMesh(id: MeshId): void;
|
|
285
|
+
getMesh(id: MeshId): THREE.Mesh | undefined;
|
|
286
|
+
|
|
287
|
+
// Model loading
|
|
288
|
+
loadModel(
|
|
289
|
+
url: string,
|
|
290
|
+
position?: [number, number, number],
|
|
291
|
+
options?: MeshOptions
|
|
292
|
+
): Promise<MeshId>;
|
|
293
|
+
playAnimation(
|
|
294
|
+
meshId: MeshId,
|
|
295
|
+
nameOrIndex?: string | number,
|
|
296
|
+
loop?: boolean,
|
|
297
|
+
timeScale?: number
|
|
298
|
+
): void;
|
|
299
|
+
updateAnimations(dt: number): void;
|
|
300
|
+
loadTexture(url: string): Promise<THREE.Texture>;
|
|
301
|
+
|
|
302
|
+
// Transforms
|
|
303
|
+
setPosition(meshId: MeshId, x: number, y: number, z: number): void;
|
|
304
|
+
setRotation(meshId: MeshId, x: number, y: number, z: number): void;
|
|
305
|
+
setScale(meshId: MeshId, x: number, y: number, z: number): void;
|
|
306
|
+
getPosition(meshId: MeshId): { x: number; y: number; z: number } | null;
|
|
307
|
+
getRotation(meshId: MeshId): { x: number; y: number; z: number } | null;
|
|
308
|
+
rotateMesh(meshId: MeshId, dX: number, dY: number, dZ: number): void;
|
|
309
|
+
moveMesh(meshId: MeshId, x: number, y: number, z: number): void;
|
|
310
|
+
|
|
311
|
+
// Mesh helpers
|
|
312
|
+
setFlatShading(meshId: MeshId, enabled?: boolean): void;
|
|
313
|
+
setMeshVisible(meshId: MeshId, visible: boolean): void;
|
|
314
|
+
setMeshOpacity(meshId: MeshId, opacity: number): void;
|
|
315
|
+
setCastShadow(meshId: MeshId, cast: boolean): void;
|
|
316
|
+
setReceiveShadow(meshId: MeshId, receive: boolean): void;
|
|
317
|
+
|
|
318
|
+
// Camera
|
|
319
|
+
setCameraPosition(x: number, y: number, z: number): void;
|
|
320
|
+
setCameraTarget(x: number, y: number, z: number): void;
|
|
321
|
+
setCameraLookAt(direction: [number, number, number]): void;
|
|
322
|
+
setCameraFOV(fov: number): void;
|
|
323
|
+
|
|
324
|
+
// Atmosphere
|
|
325
|
+
setFog(color: Color, near?: number, far?: number): void;
|
|
326
|
+
clearFog(): void;
|
|
327
|
+
setLightDirection(x: number, y: number, z: number): void;
|
|
328
|
+
setLightColor(color: Color): void;
|
|
329
|
+
setAmbientLight(color: Color, intensity?: number): void;
|
|
330
|
+
setDirectionalLight(direction: [number, number, number], color?: Color, intensity?: number): void;
|
|
331
|
+
|
|
332
|
+
// Scene
|
|
333
|
+
clearScene(): void;
|
|
334
|
+
setupScene(opts?: { fog?: boolean; grid?: boolean; axes?: boolean }): void;
|
|
335
|
+
|
|
336
|
+
// Effects
|
|
337
|
+
enablePixelation(factor?: number): void;
|
|
338
|
+
enableDithering(enabled?: boolean): void;
|
|
339
|
+
|
|
340
|
+
// Dynamic lights
|
|
341
|
+
createPointLight(
|
|
342
|
+
color?: Color,
|
|
343
|
+
intensity?: number,
|
|
344
|
+
distance?: number,
|
|
345
|
+
x?: number,
|
|
346
|
+
y?: number,
|
|
347
|
+
z?: number
|
|
348
|
+
): LightId;
|
|
349
|
+
setPointLightPosition(lightId: LightId, x: number, y: number, z: number): void;
|
|
350
|
+
setPointLightColor(lightId: LightId, color: Color): void;
|
|
351
|
+
removeLight(lightId: LightId): void;
|
|
352
|
+
|
|
353
|
+
// GPU instancing
|
|
354
|
+
createInstancedMesh(
|
|
355
|
+
shape?: 'cube' | 'sphere' | 'plane' | 'cylinder',
|
|
356
|
+
count?: number,
|
|
357
|
+
color?: Color,
|
|
358
|
+
options?: MeshOptions
|
|
359
|
+
): InstancedMeshId;
|
|
360
|
+
setInstanceTransform(
|
|
361
|
+
instancedId: InstancedMeshId,
|
|
362
|
+
index: number,
|
|
363
|
+
x?: number,
|
|
364
|
+
y?: number,
|
|
365
|
+
z?: number,
|
|
366
|
+
rx?: number,
|
|
367
|
+
ry?: number,
|
|
368
|
+
rz?: number,
|
|
369
|
+
sx?: number,
|
|
370
|
+
sy?: number,
|
|
371
|
+
sz?: number
|
|
372
|
+
): boolean;
|
|
373
|
+
setInstanceColor(instancedId: InstancedMeshId, index: number, color: Color): boolean;
|
|
374
|
+
finalizeInstances(instancedId: InstancedMeshId): boolean;
|
|
375
|
+
removeInstancedMesh(instancedId: InstancedMeshId): boolean;
|
|
376
|
+
|
|
377
|
+
// GPU particle system
|
|
378
|
+
createParticleSystem(maxParticles?: number, options?: ParticleSystemOptions): ParticleSystemId;
|
|
379
|
+
setParticleEmitter(systemId: ParticleSystemId, emitter: Partial<ParticleEmitter>): void;
|
|
380
|
+
emitParticle(systemId: ParticleSystemId, overrides?: Partial<ParticleOverrides>): void;
|
|
381
|
+
burstParticles(
|
|
382
|
+
systemId: ParticleSystemId,
|
|
383
|
+
count?: number,
|
|
384
|
+
overrides?: Partial<ParticleOverrides>
|
|
385
|
+
): void;
|
|
386
|
+
updateParticles(dt: number): void;
|
|
387
|
+
removeParticleSystem(systemId: ParticleSystemId): boolean;
|
|
388
|
+
getParticleStats(
|
|
389
|
+
systemId: ParticleSystemId
|
|
390
|
+
): { active: number; max: number; free: number } | null;
|
|
391
|
+
|
|
392
|
+
// LOD system
|
|
393
|
+
createLODMesh(levels?: LODLevel[], position?: [number, number, number]): LODId;
|
|
394
|
+
setLODPosition(lodId: LODId, x: number, y: number, z: number): void;
|
|
395
|
+
removeLODMesh(lodId: LODId): boolean;
|
|
396
|
+
updateLODs(): void;
|
|
397
|
+
|
|
398
|
+
// Normal / PBR maps
|
|
399
|
+
loadNormalMap(url: string): Promise<THREE.Texture>;
|
|
400
|
+
setNormalMap(meshId: MeshId, texture: THREE.Texture): void;
|
|
401
|
+
setPBRMaps(meshId: MeshId, maps?: PBRMaps): void;
|
|
402
|
+
|
|
403
|
+
// Raycasting / stats
|
|
404
|
+
raycastFromCamera(x: number, y: number): THREE.Intersection | null;
|
|
405
|
+
get3DStats(): Stats3D;
|
|
406
|
+
|
|
407
|
+
// Direct Three.js access
|
|
408
|
+
getScene(): THREE.Scene;
|
|
409
|
+
getCamera(): THREE.PerspectiveCamera;
|
|
410
|
+
getRenderer(): THREE.WebGLRenderer;
|
|
411
|
+
|
|
412
|
+
exposeTo(target: object): void;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export declare function threeDApi(gpu: unknown): ThreeDApiInstance;
|
|
416
|
+
|
|
417
|
+
// ---------------------------------------------------------------------------
|
|
418
|
+
// UI API
|
|
419
|
+
// ---------------------------------------------------------------------------
|
|
420
|
+
|
|
421
|
+
export interface UIApiInstance {
|
|
422
|
+
// Font / text
|
|
423
|
+
setFont(fontName: string): void;
|
|
424
|
+
getFont(): string;
|
|
425
|
+
setTextAlign(align: CanvasTextAlign): void;
|
|
426
|
+
setTextBaseline(baseline: CanvasTextBaseline): void;
|
|
427
|
+
measureText(text: string, scale?: number): number;
|
|
428
|
+
drawText(text: string, x: number, y: number, color?: Color, scale?: number): void;
|
|
429
|
+
drawTextShadow(
|
|
430
|
+
text: string,
|
|
431
|
+
x: number,
|
|
432
|
+
y: number,
|
|
433
|
+
color?: Color,
|
|
434
|
+
shadowColor?: Color,
|
|
435
|
+
scale?: number
|
|
436
|
+
): void;
|
|
437
|
+
drawTextOutline(
|
|
438
|
+
text: string,
|
|
439
|
+
x: number,
|
|
440
|
+
y: number,
|
|
441
|
+
color?: Color,
|
|
442
|
+
outlineColor?: Color,
|
|
443
|
+
scale?: number
|
|
444
|
+
): void;
|
|
445
|
+
|
|
446
|
+
// Panels
|
|
447
|
+
createPanel(x: number, y: number, width: number, height: number, options?: PanelOptions): Panel;
|
|
448
|
+
drawPanel(panel: Panel): void;
|
|
449
|
+
drawAllPanels(): void;
|
|
450
|
+
removePanel(panel: Panel): void;
|
|
451
|
+
clearPanels(): void;
|
|
452
|
+
|
|
453
|
+
// Buttons
|
|
454
|
+
createButton(
|
|
455
|
+
x: number,
|
|
456
|
+
y: number,
|
|
457
|
+
width: number,
|
|
458
|
+
height: number,
|
|
459
|
+
text: string,
|
|
460
|
+
callback: () => void,
|
|
461
|
+
options?: ButtonOptions
|
|
462
|
+
): Button;
|
|
463
|
+
updateButton(button: Button): void;
|
|
464
|
+
drawButton(button: Button): void;
|
|
465
|
+
updateAllButtons(): void;
|
|
466
|
+
drawAllButtons(): void;
|
|
467
|
+
removeButton(button: Button): void;
|
|
468
|
+
clearButtons(): void;
|
|
469
|
+
|
|
470
|
+
// Progress bar
|
|
471
|
+
drawProgressBar(
|
|
472
|
+
x: number,
|
|
473
|
+
y: number,
|
|
474
|
+
width: number,
|
|
475
|
+
height: number,
|
|
476
|
+
value: number,
|
|
477
|
+
maxValue: number,
|
|
478
|
+
options?: ProgressBarOptions
|
|
479
|
+
): void;
|
|
480
|
+
|
|
481
|
+
// Shapes
|
|
482
|
+
drawRoundedRect(
|
|
483
|
+
x: number,
|
|
484
|
+
y: number,
|
|
485
|
+
width: number,
|
|
486
|
+
height: number,
|
|
487
|
+
radius: number,
|
|
488
|
+
color: Color,
|
|
489
|
+
filled?: boolean
|
|
490
|
+
): void;
|
|
491
|
+
drawGradientRect(
|
|
492
|
+
x: number,
|
|
493
|
+
y: number,
|
|
494
|
+
width: number,
|
|
495
|
+
height: number,
|
|
496
|
+
color1: Color,
|
|
497
|
+
color2: Color,
|
|
498
|
+
vertical?: boolean
|
|
499
|
+
): void;
|
|
500
|
+
|
|
501
|
+
// Layout
|
|
502
|
+
centerX(width: number, screenWidth?: number): number;
|
|
503
|
+
centerY(height: number, screenHeight?: number): number;
|
|
504
|
+
grid(
|
|
505
|
+
cols: number,
|
|
506
|
+
rows: number,
|
|
507
|
+
cellWidth: number,
|
|
508
|
+
cellHeight: number,
|
|
509
|
+
paddingX?: number,
|
|
510
|
+
paddingY?: number
|
|
511
|
+
): Array<{ x: number; y: number; col: number; row: number }>;
|
|
512
|
+
|
|
513
|
+
// Mouse
|
|
514
|
+
setMousePosition(x: number, y: number): void;
|
|
515
|
+
setMouseButton(down: boolean): void;
|
|
516
|
+
getMousePosition(): MousePosition;
|
|
517
|
+
isMouseDown(): boolean;
|
|
518
|
+
isMousePressed(): boolean;
|
|
519
|
+
|
|
520
|
+
// Palettes
|
|
521
|
+
uiColors: Record<string, Color>;
|
|
522
|
+
uiFonts: Record<string, string>;
|
|
523
|
+
|
|
524
|
+
exposeTo(target: object): void;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export declare function uiApi(ctx2d: CanvasRenderingContext2D | null): UIApiInstance;
|
|
528
|
+
|
|
529
|
+
// ---------------------------------------------------------------------------
|
|
530
|
+
// Sub-module factory types (for tree-shaking imports)
|
|
531
|
+
// ---------------------------------------------------------------------------
|
|
532
|
+
|
|
533
|
+
export declare function materialsModule(ctx: object): object;
|
|
534
|
+
export declare function primitivesModule(ctx: object): object;
|
|
535
|
+
export declare function transformsModule(ctx: object): object;
|
|
536
|
+
export declare function cameraModule(ctx: object): object;
|
|
537
|
+
export declare function lightsModule(ctx: object): object;
|
|
538
|
+
export declare function modelsModule(ctx: object): object;
|
|
539
|
+
export declare function instancingModule(ctx: object): object;
|
|
540
|
+
export declare function pbrModule(ctx: object): object;
|
|
541
|
+
export declare function sceneModule(ctx: object): object;
|
|
542
|
+
|
|
543
|
+
export declare function uiTextModule(ctx: object): object;
|
|
544
|
+
export declare function uiPanelsModule(ctx: object): object;
|
|
545
|
+
export declare function uiButtonsModule(ctx: object): object;
|
|
546
|
+
export declare function uiWidgetsModule(ctx: object): object;
|
|
547
|
+
|
|
548
|
+
// ---------------------------------------------------------------------------
|
|
549
|
+
// Global cart API (injected into globalThis at runtime)
|
|
550
|
+
// Augment with: declare global { ... } in your cart's .d.ts if needed.
|
|
551
|
+
// ---------------------------------------------------------------------------
|
|
552
|
+
|
|
553
|
+
export interface Nova64CartGlobals {
|
|
554
|
+
// 3D
|
|
555
|
+
createCube: ThreeDApiInstance['createCube'];
|
|
556
|
+
createSphere: ThreeDApiInstance['createSphere'];
|
|
557
|
+
createCylinder: ThreeDApiInstance['createCylinder'];
|
|
558
|
+
createPlane: ThreeDApiInstance['createPlane'];
|
|
559
|
+
createTorus: ThreeDApiInstance['createTorus'];
|
|
560
|
+
createCone: ThreeDApiInstance['createCone'];
|
|
561
|
+
createCapsule: ThreeDApiInstance['createCapsule'];
|
|
562
|
+
createAdvancedCube: ThreeDApiInstance['createAdvancedCube'];
|
|
563
|
+
createAdvancedSphere: ThreeDApiInstance['createAdvancedSphere'];
|
|
564
|
+
destroyMesh: ThreeDApiInstance['destroyMesh'];
|
|
565
|
+
removeMesh: ThreeDApiInstance['removeMesh'];
|
|
566
|
+
getMesh: ThreeDApiInstance['getMesh'];
|
|
567
|
+
loadModel: ThreeDApiInstance['loadModel'];
|
|
568
|
+
playAnimation: ThreeDApiInstance['playAnimation'];
|
|
569
|
+
updateAnimations: ThreeDApiInstance['updateAnimations'];
|
|
570
|
+
loadTexture: ThreeDApiInstance['loadTexture'];
|
|
571
|
+
setPosition: ThreeDApiInstance['setPosition'];
|
|
572
|
+
setRotation: ThreeDApiInstance['setRotation'];
|
|
573
|
+
setScale: ThreeDApiInstance['setScale'];
|
|
574
|
+
getPosition: ThreeDApiInstance['getPosition'];
|
|
575
|
+
getRotation: ThreeDApiInstance['getRotation'];
|
|
576
|
+
rotateMesh: ThreeDApiInstance['rotateMesh'];
|
|
577
|
+
moveMesh: ThreeDApiInstance['moveMesh'];
|
|
578
|
+
setFlatShading: ThreeDApiInstance['setFlatShading'];
|
|
579
|
+
setMeshVisible: ThreeDApiInstance['setMeshVisible'];
|
|
580
|
+
setMeshOpacity: ThreeDApiInstance['setMeshOpacity'];
|
|
581
|
+
setCastShadow: ThreeDApiInstance['setCastShadow'];
|
|
582
|
+
setReceiveShadow: ThreeDApiInstance['setReceiveShadow'];
|
|
583
|
+
setCameraPosition: ThreeDApiInstance['setCameraPosition'];
|
|
584
|
+
setCameraTarget: ThreeDApiInstance['setCameraTarget'];
|
|
585
|
+
setCameraLookAt: ThreeDApiInstance['setCameraLookAt'];
|
|
586
|
+
setCameraFOV: ThreeDApiInstance['setCameraFOV'];
|
|
587
|
+
setFog: ThreeDApiInstance['setFog'];
|
|
588
|
+
clearFog: ThreeDApiInstance['clearFog'];
|
|
589
|
+
setLightDirection: ThreeDApiInstance['setLightDirection'];
|
|
590
|
+
setLightColor: ThreeDApiInstance['setLightColor'];
|
|
591
|
+
setAmbientLight: ThreeDApiInstance['setAmbientLight'];
|
|
592
|
+
setDirectionalLight: ThreeDApiInstance['setDirectionalLight'];
|
|
593
|
+
clearScene: ThreeDApiInstance['clearScene'];
|
|
594
|
+
enablePixelation: ThreeDApiInstance['enablePixelation'];
|
|
595
|
+
enableDithering: ThreeDApiInstance['enableDithering'];
|
|
596
|
+
createPointLight: ThreeDApiInstance['createPointLight'];
|
|
597
|
+
setPointLightPosition: ThreeDApiInstance['setPointLightPosition'];
|
|
598
|
+
setPointLightColor: ThreeDApiInstance['setPointLightColor'];
|
|
599
|
+
removeLight: ThreeDApiInstance['removeLight'];
|
|
600
|
+
createInstancedMesh: ThreeDApiInstance['createInstancedMesh'];
|
|
601
|
+
setInstanceTransform: ThreeDApiInstance['setInstanceTransform'];
|
|
602
|
+
setInstanceColor: ThreeDApiInstance['setInstanceColor'];
|
|
603
|
+
finalizeInstances: ThreeDApiInstance['finalizeInstances'];
|
|
604
|
+
removeInstancedMesh: ThreeDApiInstance['removeInstancedMesh'];
|
|
605
|
+
createParticleSystem: ThreeDApiInstance['createParticleSystem'];
|
|
606
|
+
setParticleEmitter: ThreeDApiInstance['setParticleEmitter'];
|
|
607
|
+
emitParticle: ThreeDApiInstance['emitParticle'];
|
|
608
|
+
burstParticles: ThreeDApiInstance['burstParticles'];
|
|
609
|
+
updateParticles: ThreeDApiInstance['updateParticles'];
|
|
610
|
+
removeParticleSystem: ThreeDApiInstance['removeParticleSystem'];
|
|
611
|
+
getParticleStats: ThreeDApiInstance['getParticleStats'];
|
|
612
|
+
createLODMesh: ThreeDApiInstance['createLODMesh'];
|
|
613
|
+
setLODPosition: ThreeDApiInstance['setLODPosition'];
|
|
614
|
+
removeLODMesh: ThreeDApiInstance['removeLODMesh'];
|
|
615
|
+
updateLODs: ThreeDApiInstance['updateLODs'];
|
|
616
|
+
loadNormalMap: ThreeDApiInstance['loadNormalMap'];
|
|
617
|
+
setNormalMap: ThreeDApiInstance['setNormalMap'];
|
|
618
|
+
setPBRMaps: ThreeDApiInstance['setPBRMaps'];
|
|
619
|
+
raycastFromCamera: ThreeDApiInstance['raycastFromCamera'];
|
|
620
|
+
get3DStats: ThreeDApiInstance['get3DStats'];
|
|
621
|
+
getScene: ThreeDApiInstance['getScene'];
|
|
622
|
+
getCamera: ThreeDApiInstance['getCamera'];
|
|
623
|
+
getRenderer: ThreeDApiInstance['getRenderer'];
|
|
624
|
+
|
|
625
|
+
// UI
|
|
626
|
+
setFont: UIApiInstance['setFont'];
|
|
627
|
+
getFont: UIApiInstance['getFont'];
|
|
628
|
+
setTextAlign: UIApiInstance['setTextAlign'];
|
|
629
|
+
setTextBaseline: UIApiInstance['setTextBaseline'];
|
|
630
|
+
measureText: UIApiInstance['measureText'];
|
|
631
|
+
drawText: UIApiInstance['drawText'];
|
|
632
|
+
drawTextShadow: UIApiInstance['drawTextShadow'];
|
|
633
|
+
drawTextOutline: UIApiInstance['drawTextOutline'];
|
|
634
|
+
createPanel: UIApiInstance['createPanel'];
|
|
635
|
+
drawPanel: UIApiInstance['drawPanel'];
|
|
636
|
+
drawAllPanels: UIApiInstance['drawAllPanels'];
|
|
637
|
+
removePanel: UIApiInstance['removePanel'];
|
|
638
|
+
clearPanels: UIApiInstance['clearPanels'];
|
|
639
|
+
createButton: UIApiInstance['createButton'];
|
|
640
|
+
updateButton: UIApiInstance['updateButton'];
|
|
641
|
+
drawButton: UIApiInstance['drawButton'];
|
|
642
|
+
updateAllButtons: UIApiInstance['updateAllButtons'];
|
|
643
|
+
drawAllButtons: UIApiInstance['drawAllButtons'];
|
|
644
|
+
removeButton: UIApiInstance['removeButton'];
|
|
645
|
+
clearButtons: UIApiInstance['clearButtons'];
|
|
646
|
+
drawProgressBar: UIApiInstance['drawProgressBar'];
|
|
647
|
+
drawRoundedRect: UIApiInstance['drawRoundedRect'];
|
|
648
|
+
drawGradientRect: UIApiInstance['drawGradientRect'];
|
|
649
|
+
centerX: UIApiInstance['centerX'];
|
|
650
|
+
centerY: UIApiInstance['centerY'];
|
|
651
|
+
grid: UIApiInstance['grid'];
|
|
652
|
+
setMousePosition: UIApiInstance['setMousePosition'];
|
|
653
|
+
setMouseButton: UIApiInstance['setMouseButton'];
|
|
654
|
+
getMousePosition: UIApiInstance['getMousePosition'];
|
|
655
|
+
isMouseDown: UIApiInstance['isMouseDown'];
|
|
656
|
+
isMousePressed: UIApiInstance['isMousePressed'];
|
|
657
|
+
uiColors: UIApiInstance['uiColors'];
|
|
658
|
+
uiFonts: UIApiInstance['uiFonts'];
|
|
659
|
+
|
|
660
|
+
// Input (runtime/input.js)
|
|
661
|
+
key(code: string): boolean;
|
|
662
|
+
keyp(code: string): boolean;
|
|
663
|
+
btn(index: number): boolean;
|
|
664
|
+
btnp(index: number): boolean;
|
|
665
|
+
|
|
666
|
+
// 2D drawing (runtime/framebuffer.js / api-2d.js)
|
|
667
|
+
cls(color?: Color): void;
|
|
668
|
+
print(text: string, x: number, y: number, color?: Color, scale?: number): void;
|
|
669
|
+
printCentered(text: string, y: number, color?: Color, scale?: number): void;
|
|
670
|
+
line(x1: number, y1: number, x2: number, y2: number, color?: Color): void;
|
|
671
|
+
circle(x: number, y: number, r: number, color?: Color, filled?: boolean): void;
|
|
672
|
+
drawRect(x: number, y: number, w: number, h: number, color?: Color): void;
|
|
673
|
+
rgba8(r: number, g: number, b: number, a: number): Color;
|
|
674
|
+
|
|
675
|
+
// Storage (runtime/storage.js)
|
|
676
|
+
saveData(key: string, value: unknown): void;
|
|
677
|
+
loadData(key: string, fallback?: unknown): unknown;
|
|
678
|
+
deleteData(key: string): void;
|
|
679
|
+
|
|
680
|
+
// Audio (runtime/audio.js)
|
|
681
|
+
sfx(preset: string | { wave?: string; freq?: number; dur?: number; vol?: number }): void;
|
|
682
|
+
}
|