@needle-tools/engine 5.1.0-canary.e9062c0 → 5.1.0-canary.fbdfce3
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/CHANGELOG.md +34 -0
- package/dist/{needle-engine.bundle-CDKcuALa.js → needle-engine.bundle-BFSj2Fz8.js} +5420 -5413
- package/dist/{needle-engine.bundle-w22UkaT_.min.js → needle-engine.bundle-CmxIO5uH.min.js} +135 -135
- package/dist/{needle-engine.bundle--q_w7iXI.umd.cjs → needle-engine.bundle-tJIZukCz.umd.cjs} +135 -135
- package/dist/needle-engine.d.ts +57 -65
- package/dist/needle-engine.js +188 -186
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/debug/debug_spatial_console.d.ts +2 -0
- package/lib/engine/debug/debug_spatial_console.js +10 -7
- package/lib/engine/debug/debug_spatial_console.js.map +1 -1
- package/lib/engine/engine_addressables.d.ts +2 -0
- package/lib/engine/engine_addressables.js +6 -3
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_context.d.ts +16 -19
- package/lib/engine/engine_context.js +12 -15
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_init.js +10 -0
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_scenedata.d.ts +5 -7
- package/lib/engine/engine_scenedata.js +14 -11
- package/lib/engine/engine_scenedata.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.d.ts +10 -16
- package/lib/engine/engine_serialization_builtin_serializer.js +28 -41
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/webcomponents/jsx.d.ts +9 -2
- package/lib/engine-components/AnimatorController.d.ts +2 -0
- package/lib/engine-components/AnimatorController.js +4 -1
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/Light.js +4 -2
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.js +2 -0
- package/lib/engine-components/ReflectionProbe.js.map +1 -1
- package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
- package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
- package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
- package/package.json +1 -1
- package/plugins/vite/reload.js +18 -17
- package/src/engine/debug/debug_spatial_console.ts +10 -7
- package/src/engine/engine_addressables.ts +6 -3
- package/src/engine/engine_context.ts +18 -20
- package/src/engine/engine_init.ts +10 -0
- package/src/engine/engine_scenedata.ts +13 -10
- package/src/engine/engine_serialization_builtin_serializer.ts +32 -43
- package/src/engine/webcomponents/jsx.d.ts +9 -2
- package/src/engine-components/AnimatorController.ts +4 -1
- package/src/engine-components/Light.ts +3 -2
- package/src/engine-components/ReflectionProbe.ts +2 -0
- package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
package/plugins/vite/reload.js
CHANGED
|
@@ -7,6 +7,7 @@ import { existsSync, readFileSync, statSync } from 'fs';
|
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import { needleLog } from './logging.js';
|
|
9
9
|
|
|
10
|
+
const pluginName = "needle-reload";
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = path.dirname(__filename);
|
|
12
13
|
|
|
@@ -39,7 +40,7 @@ export function needleReload(_command, config, userSettings) {
|
|
|
39
40
|
const buildDirectory = projectConfig?.buildDirectory?.length ? process.cwd().replaceAll("\\", "/") + "/" + projectConfig?.buildDirectory : "";
|
|
40
41
|
if (buildDirectory?.length) {
|
|
41
42
|
const relativeBuildDirectory = path.relative(process.cwd(), buildDirectory).replaceAll("\\", "/") || ".";
|
|
42
|
-
setTimeout(() => needleLog(
|
|
43
|
+
setTimeout(() => needleLog(pluginName, "Build directory: " + relativeBuildDirectory), 100);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
// These ignore patterns will be injected into user config to better control vite reloading
|
|
@@ -59,7 +60,7 @@ export function needleReload(_command, config, userSettings) {
|
|
|
59
60
|
// @ts-ignore - watch.ignored is guaranteed to be string[] by the guards above
|
|
60
61
|
config.server.watch.ignored.push(pattern);
|
|
61
62
|
if (userSettings?.debug === true)
|
|
62
|
-
setTimeout(() => needleLog(
|
|
63
|
+
setTimeout(() => needleLog(pluginName, "Updated server ignore patterns: " + JSON.stringify(config.server?.watch?.ignored)), 100);
|
|
63
64
|
},
|
|
64
65
|
/** @param {import('vite').HmrContext & {buildDirectory?: string}} args */
|
|
65
66
|
handleHotUpdate(args) {
|
|
@@ -118,7 +119,7 @@ function getHot(server) {
|
|
|
118
119
|
|
|
119
120
|
/** @param {import('vite').ViteDevServer} server @param {string} [file] */
|
|
120
121
|
function notifyClientWillReload(server, file) {
|
|
121
|
-
|
|
122
|
+
needleLog(pluginName, "Send reload notification");
|
|
122
123
|
getHot(server).send('needle:reload', { type: 'will-reload', file: file });
|
|
123
124
|
}
|
|
124
125
|
|
|
@@ -134,7 +135,7 @@ async function handleReload({ file, server, modules: _modules, read, buildDirect
|
|
|
134
135
|
|
|
135
136
|
// Dont reload the whole server when a file that is using hot reload changes
|
|
136
137
|
if (filesUsingHotReload.has(file)) {
|
|
137
|
-
|
|
138
|
+
needleLog(pluginName, "File is using hot reload: " + file);
|
|
138
139
|
return null;
|
|
139
140
|
}
|
|
140
141
|
|
|
@@ -153,7 +154,7 @@ async function handleReload({ file, server, modules: _modules, read, buildDirect
|
|
|
153
154
|
// instead of relying on the vite server watch ignore array
|
|
154
155
|
// we could here also match paths that we know we dont want to track
|
|
155
156
|
if (ignorePatterns.length > 0 && ignoreRegex.test(file)) {
|
|
156
|
-
|
|
157
|
+
needleLog(pluginName, "Ignore change in file: " + getFileNameLog(file));
|
|
157
158
|
return [];
|
|
158
159
|
}
|
|
159
160
|
|
|
@@ -163,7 +164,7 @@ async function handleReload({ file, server, modules: _modules, read, buildDirect
|
|
|
163
164
|
if (buildDirectory?.length) {
|
|
164
165
|
const dir = path.dirname(file).replaceAll("\\", "/");
|
|
165
166
|
if (dir.startsWith(buildDirectory)) {
|
|
166
|
-
|
|
167
|
+
needleLog(pluginName, "Ignore change in build directory: " + getFileNameLog(file));
|
|
167
168
|
return [];
|
|
168
169
|
}
|
|
169
170
|
}
|
|
@@ -178,13 +179,13 @@ async function handleReload({ file, server, modules: _modules, read, buildDirect
|
|
|
178
179
|
return [];
|
|
179
180
|
}
|
|
180
181
|
if (await testIfFileContentChanged(file, read) === false) {
|
|
181
|
-
|
|
182
|
+
needleLog(pluginName, "File content didnt change: " + getFileNameLog(file));
|
|
182
183
|
return [];
|
|
183
184
|
}
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
// these are known file types we export from integrations
|
|
187
|
-
const knownExportFileTypes = [
|
|
188
|
+
const knownExportFileTypes = [".glb", ".gltf", ".bin", "exr", ".ktx2", ".mp3", ".ogg", ".mp4", ".webm"];
|
|
188
189
|
if (!knownExportFileTypes.some((type) => file.endsWith(type)))
|
|
189
190
|
return null;
|
|
190
191
|
|
|
@@ -208,7 +209,7 @@ async function handleReload({ file, server, modules: _modules, read, buildDirect
|
|
|
208
209
|
}
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
|
|
212
|
+
needleLog(pluginName, "> Detected file change: " + getFileNameLog(file) + " (" + ((fileSize / (1024 * 1024)).toFixed(1)) + " MB)");
|
|
212
213
|
notifyClientWillReload(server);
|
|
213
214
|
scheduleReload(server);
|
|
214
215
|
return [];
|
|
@@ -223,7 +224,7 @@ async function scheduleReload(server, level = 0) {
|
|
|
223
224
|
const lockFile = path.join(process.cwd(), lockFileName);
|
|
224
225
|
if (existsSync(lockFile)) {
|
|
225
226
|
if (level === 0)
|
|
226
|
-
|
|
227
|
+
needleLog(pluginName, "Lock file exists, waiting for export to finish...");
|
|
227
228
|
setTimeout(() => scheduleReload(server, level += 1), 300);
|
|
228
229
|
return;
|
|
229
230
|
}
|
|
@@ -234,13 +235,13 @@ async function scheduleReload(server, level = 0) {
|
|
|
234
235
|
if (timeDiff < 1000) {
|
|
235
236
|
// Sometimes file changes happen immediately after triggering a reload
|
|
236
237
|
// we dont want to reload again in that case
|
|
237
|
-
|
|
238
|
+
needleLog(pluginName, "Ignoring reload, last reload was too recent" + timeDiff + "ms ago");
|
|
238
239
|
return;
|
|
239
240
|
}
|
|
240
241
|
|
|
241
242
|
lastReloadTime = Date.now();
|
|
242
243
|
const readableTime = new Date(lastReloadTime).toLocaleTimeString();
|
|
243
|
-
|
|
244
|
+
needleLog(pluginName, "< Reloading... " + readableTime);
|
|
244
245
|
getHot(server).send({
|
|
245
246
|
type: 'full-reload',
|
|
246
247
|
path: '*'
|
|
@@ -299,10 +300,10 @@ function removeVersionQueryArgument(content) {
|
|
|
299
300
|
function insertScriptRegisterHotReloadCode(src, filePath) {
|
|
300
301
|
|
|
301
302
|
// We only want to inject the hot reload code in the needle-engine root file
|
|
302
|
-
if(!filePath.includes("/src/needle-engine.ts")) {
|
|
303
|
+
if (!filePath.includes("/src/needle-engine.ts")) {
|
|
303
304
|
return src;
|
|
304
305
|
}
|
|
305
|
-
|
|
306
|
+
needleLog(pluginName, "[Needle HMR] Hot reload is enabled");
|
|
306
307
|
// this code let's the engine know that we are in hot reload mode
|
|
307
308
|
const code = `
|
|
308
309
|
globalThis.NEEDLE_HOT_RELOAD_ENABLED = true;
|
|
@@ -338,12 +339,12 @@ function insertScriptHotReloadCode(src, filePath) {
|
|
|
338
339
|
return undefined;
|
|
339
340
|
// make import path from engine package
|
|
340
341
|
const fullPathToHotReload = process.cwd() + "/node_modules/@needle-tools/engine/src/engine/engine_hot_reload.ts";
|
|
341
|
-
//
|
|
342
|
+
// needleLog(pluginName, fullPathToHotReload);
|
|
342
343
|
const fileDirectory = path.dirname(filePath);
|
|
343
|
-
//
|
|
344
|
+
// needleLog(pluginName, "DIR", fileDirectory)
|
|
344
345
|
const relativePath = path.relative(fileDirectory, fullPathToHotReload);
|
|
345
346
|
importPath = relativePath.replace(/\\/g, "/");
|
|
346
|
-
//
|
|
347
|
+
// needleLog(pluginName, "importPath: ", importPath);
|
|
347
348
|
}
|
|
348
349
|
|
|
349
350
|
// console.log(importPath, ">", filePath);
|
|
@@ -12,13 +12,16 @@ import { onError } from "./debug_overlay.js";
|
|
|
12
12
|
|
|
13
13
|
let _isActive = false;
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
/** @internal */
|
|
16
|
+
export function initSpatialConsole() {
|
|
17
|
+
// enable the spatial console if we receive an error while in dev session and in XR
|
|
18
|
+
onError((...args: any[]) => {
|
|
19
|
+
if (isDevEnvironment() && ContextRegistry.Current?.isInXR) {
|
|
20
|
+
enableSpatialConsole(true);
|
|
21
|
+
onLog("error", ...args);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
/** Enable a spatial debug console that follows the camera */
|
|
@@ -567,7 +567,6 @@ class AddressableSerializer extends TypeSerializer {
|
|
|
567
567
|
}
|
|
568
568
|
|
|
569
569
|
}
|
|
570
|
-
new AddressableSerializer();
|
|
571
570
|
|
|
572
571
|
|
|
573
572
|
|
|
@@ -703,7 +702,6 @@ export class ImageReferenceSerializer extends TypeSerializer {
|
|
|
703
702
|
return undefined;
|
|
704
703
|
}
|
|
705
704
|
}
|
|
706
|
-
new ImageReferenceSerializer();
|
|
707
705
|
|
|
708
706
|
|
|
709
707
|
|
|
@@ -772,4 +770,9 @@ export class FileReferenceSerializer extends TypeSerializer {
|
|
|
772
770
|
return undefined;
|
|
773
771
|
}
|
|
774
772
|
}
|
|
775
|
-
|
|
773
|
+
/** @internal */
|
|
774
|
+
export function initAddressableSerializers() {
|
|
775
|
+
new AddressableSerializer();
|
|
776
|
+
new ImageReferenceSerializer();
|
|
777
|
+
new FileReferenceSerializer();
|
|
778
|
+
}
|
|
@@ -478,13 +478,14 @@ export class Context implements IContext {
|
|
|
478
478
|
* Use `setCurrentCamera` for updating the main camera.
|
|
479
479
|
*/
|
|
480
480
|
/**
|
|
481
|
-
*
|
|
482
|
-
* Types are
|
|
483
|
-
* and written to `src/generated/needle-bindings.d.ts` on every dev-server start and GLB change.
|
|
481
|
+
* Access your scene's full hierarchy, objects, and components directly by name — with full autocomplete.
|
|
482
|
+
* Types are generated automatically from your GLB files when the dev server starts.
|
|
484
483
|
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
484
|
+
* You can store references to objects or components for later use.
|
|
485
|
+
* Note that the scene hierarchy can change at runtime (e.g. when objects are added, removed, or re-parented),
|
|
486
|
+
* in which case stored references may become stale.
|
|
487
|
+
*
|
|
488
|
+
* @experimental This API may change in future versions.
|
|
488
489
|
*
|
|
489
490
|
* @example
|
|
490
491
|
* // Toggle auto-rotate on the orbit camera
|
|
@@ -493,12 +494,6 @@ export class Context implements IContext {
|
|
|
493
494
|
* @example
|
|
494
495
|
* // Change the background color
|
|
495
496
|
* ctx.sceneData.Camera.Camera.backgroundColor = new RGBAColor(1, 0, 0, 1);
|
|
496
|
-
*
|
|
497
|
-
* @example
|
|
498
|
-
* // Equivalent manual approach (without sceneData)
|
|
499
|
-
* const node = ctx.scene.getObjectByName("Camera");
|
|
500
|
-
* const orbit = getComponent(node, OrbitControls);
|
|
501
|
-
* if (orbit) orbit.autoRotate = true;
|
|
502
497
|
*/
|
|
503
498
|
get sceneData(): SceneData {
|
|
504
499
|
return getSceneData(this);
|
|
@@ -543,8 +538,10 @@ export class Context implements IContext {
|
|
|
543
538
|
/** @deprecated AssetDatabase is deprecated */
|
|
544
539
|
assets: AssetDatabase;
|
|
545
540
|
|
|
546
|
-
/** All registered lights in the scene, maintained by the Light component
|
|
547
|
-
|
|
541
|
+
/** All registered lights in the scene, maintained by the Light component.
|
|
542
|
+
* @see mainLight for accessing the main directional light in the scene
|
|
543
|
+
*/
|
|
544
|
+
readonly lights = new Array<ILight>();
|
|
548
545
|
|
|
549
546
|
/** The brightest registered directional light, or null if none are registered
|
|
550
547
|
* @see lights
|
|
@@ -559,12 +556,13 @@ export class Context implements IContext {
|
|
|
559
556
|
}
|
|
560
557
|
|
|
561
558
|
/** @deprecated Use sceneLighting */
|
|
562
|
-
get rendererData() { return this.sceneLighting }
|
|
559
|
+
private get rendererData() { return this.sceneLighting }
|
|
560
|
+
|
|
563
561
|
/** Access the scene lighting manager to control lighting settings in the context */
|
|
564
|
-
sceneLighting: SceneLighting;
|
|
565
|
-
addressables: Addressables;
|
|
566
|
-
lightmaps: ILightDataRegistry;
|
|
567
|
-
players: PlayerViewManager;
|
|
562
|
+
readonly sceneLighting: SceneLighting;
|
|
563
|
+
readonly addressables: Addressables;
|
|
564
|
+
readonly lightmaps: ILightDataRegistry;
|
|
565
|
+
readonly players: PlayerViewManager;
|
|
568
566
|
|
|
569
567
|
/** Access the LODs manager to control LOD behavior in the context */
|
|
570
568
|
readonly lodsManager: LODsManager;
|
|
@@ -872,7 +870,7 @@ export class Context implements IContext {
|
|
|
872
870
|
this._onBeforeRenderListeners.clear();
|
|
873
871
|
this._onAfterRenderListeners.clear();
|
|
874
872
|
|
|
875
|
-
this.lights.
|
|
873
|
+
this.lights.length = 0;
|
|
876
874
|
|
|
877
875
|
if (!this.isManagedExternally) {
|
|
878
876
|
if (this.renderer) {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { initAnimatorControllerSerializer } from "../engine-components/AnimatorController.js";
|
|
1
2
|
import { initAnimationAutoplay } from "../engine-components/AnimationUtilsAutoplay.js";
|
|
2
3
|
import { initCameraUtils } from "../engine-components/CameraUtils.js";
|
|
4
|
+
import { initVolumeParameterSerializer } from "../engine-components/postprocessing/VolumeParameter.js";
|
|
3
5
|
import { initSceneSwitcherAttributes } from "../engine-components/SceneSwitcher.js";
|
|
4
6
|
import { initSkyboxAttributes } from "../engine-components/Skybox.js";
|
|
7
|
+
import { initAddressableSerializers } from "./engine_addressables.js";
|
|
5
8
|
import { initBuiltinTypes } from "./codegen/register_types.js";
|
|
6
9
|
import { ensureAudioContextIsResumed } from "./engine_audio.js";
|
|
7
10
|
import { initNeedleLoader } from "./engine_loaders.js";
|
|
11
|
+
import { initBuiltinSerializers } from "./engine_serialization_builtin_serializer.js";
|
|
8
12
|
import { initShims } from "./engine_shims.js";
|
|
9
13
|
import { patchTonemapping } from "./engine_tonemapping.js";
|
|
10
14
|
import { initCameraExtensions } from "./js-extensions/Camera.js";
|
|
@@ -15,6 +19,7 @@ import { SSR } from "./engine_ssr.js";
|
|
|
15
19
|
import { initLicense } from "./engine_license.js";
|
|
16
20
|
import { initWebComponents } from "./webcomponents/init.js";
|
|
17
21
|
import { initPhysics } from "./engine_physics_rapier.js";
|
|
22
|
+
import { initSpatialConsole } from "./debug/debug_spatial_console.js";
|
|
18
23
|
import { initXR } from "./xr/init.js";
|
|
19
24
|
|
|
20
25
|
let initialized = false;
|
|
@@ -35,6 +40,10 @@ export function initEngine() {
|
|
|
35
40
|
|
|
36
41
|
initWebComponents();
|
|
37
42
|
initShims();
|
|
43
|
+
initBuiltinSerializers();
|
|
44
|
+
initAddressableSerializers();
|
|
45
|
+
initAnimatorControllerSerializer();
|
|
46
|
+
initVolumeParameterSerializer();
|
|
38
47
|
patchTonemapping();
|
|
39
48
|
patchLayers();
|
|
40
49
|
initCameraExtensions();
|
|
@@ -49,5 +58,6 @@ export function initEngine() {
|
|
|
49
58
|
initSceneSwitcherAttributes();
|
|
50
59
|
initPhysics();
|
|
51
60
|
initXR();
|
|
61
|
+
initSpatialConsole();
|
|
52
62
|
initLicense();
|
|
53
63
|
}
|
|
@@ -7,15 +7,13 @@ import { isDevEnvironment } from "./debug/index.js";
|
|
|
7
7
|
import { ContextRegistry } from "./engine_context_registry.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* safe to import at module level, including in SSR environments
|
|
13
|
-
* (returns a silent error proxy when no context is active).
|
|
10
|
+
* Quick access to the current Needle Engine context from anywhere — no need to pass `ctx` around.
|
|
11
|
+
* Use it in React/Svelte/Vue components, button handlers, or plain JavaScript.
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* Safe to import at module level, including in SSR environments.
|
|
14
|
+
* For pages with multiple `<needle-engine>` elements, use `ctx` directly instead.
|
|
17
15
|
*
|
|
18
|
-
*
|
|
16
|
+
* @experimental This API may change in future releases.
|
|
19
17
|
*
|
|
20
18
|
* @example
|
|
21
19
|
* import { needle } from "@needle-tools/engine";
|
|
@@ -29,7 +27,7 @@ export const needle: IContext = new Proxy({} as IContext, {
|
|
|
29
27
|
const ctx = ContextRegistry.Current;
|
|
30
28
|
if (!ctx) {
|
|
31
29
|
const fn = isDevEnvironment() ? console.error : console.warn;
|
|
32
|
-
fn(`[needle] needle.${prop} accessed before scene started`);
|
|
30
|
+
fn(`[needle] needle.${prop} was accessed before the scene started. Use "needle" inside event handlers or callbacks, not at module top-level. For setup code use: onStart(ctx => { ... })`);
|
|
33
31
|
return makeErrorProxy(`needle not ready — scene hasn't started yet`);
|
|
34
32
|
}
|
|
35
33
|
const val = (ctx as any)[prop];
|
|
@@ -39,7 +37,7 @@ export const needle: IContext = new Proxy({} as IContext, {
|
|
|
39
37
|
const ctx = ContextRegistry.Current;
|
|
40
38
|
if (!ctx) {
|
|
41
39
|
const fn = isDevEnvironment() ? console.error : console.warn;
|
|
42
|
-
fn(`[needle] needle.${prop} set before scene started`);
|
|
40
|
+
fn(`[needle] needle.${prop} was set before the scene started. Use "needle" inside event handlers or callbacks, not at module top-level. For setup code use: onStart(ctx => { ... })`);
|
|
43
41
|
return true;
|
|
44
42
|
}
|
|
45
43
|
(ctx as any)[prop] = value;
|
|
@@ -91,9 +89,14 @@ function makeNodeProxy(ctx: IContext, node: import("three").Object3D): object {
|
|
|
91
89
|
}
|
|
92
90
|
});
|
|
93
91
|
}
|
|
92
|
+
if (prop === "then") return undefined; // not a Promise
|
|
94
93
|
// Child node lookup by name
|
|
95
94
|
const child = node.children.find(c => c.name === prop) ?? null;
|
|
96
|
-
if (!child)
|
|
95
|
+
if (!child) {
|
|
96
|
+
const fn = isDevEnvironment() ? console.error : console.warn;
|
|
97
|
+
fn(`[SceneData] "${prop}" is not a child of "${node.name}". Use .$object to get the Three.js object or .$components.Name to access a component.`);
|
|
98
|
+
return makeErrorProxy(`"${prop}" not found on node "${node.name}"`);
|
|
99
|
+
}
|
|
97
100
|
return makeNodeProxy(ctx, child);
|
|
98
101
|
}
|
|
99
102
|
});
|
|
@@ -11,24 +11,6 @@ import { IComponent } from "./engine_types.js";
|
|
|
11
11
|
import { resolveUrl } from "./engine_utils.js";
|
|
12
12
|
import { RGBAColor } from "./js-extensions/index.js";
|
|
13
13
|
|
|
14
|
-
// export class SourcePath {
|
|
15
|
-
// src?:string
|
|
16
|
-
// };
|
|
17
|
-
|
|
18
|
-
// class SourcePathSerializer extends TypeSerializer{
|
|
19
|
-
// constructor(){
|
|
20
|
-
// super(SourcePath);
|
|
21
|
-
// }
|
|
22
|
-
// onDeserialize(data: any, _context: SerializationContext) {
|
|
23
|
-
// if(data.src && typeof data.src === "string"){
|
|
24
|
-
// return data.src;
|
|
25
|
-
// }
|
|
26
|
-
// }
|
|
27
|
-
// onSerialize(_data: any, _context: SerializationContext) {
|
|
28
|
-
|
|
29
|
-
// }
|
|
30
|
-
// }
|
|
31
|
-
// new SourcePathSerializer();
|
|
32
14
|
|
|
33
15
|
class ColorSerializer extends TypeSerializer {
|
|
34
16
|
constructor() {
|
|
@@ -52,7 +34,6 @@ class ColorSerializer extends TypeSerializer {
|
|
|
52
34
|
return { r: data.r, g: data.g, b: data.b }
|
|
53
35
|
}
|
|
54
36
|
}
|
|
55
|
-
export const colorSerializer = new ColorSerializer();
|
|
56
37
|
|
|
57
38
|
class EulerSerializer extends TypeSerializer {
|
|
58
39
|
constructor() {
|
|
@@ -72,7 +53,6 @@ class EulerSerializer extends TypeSerializer {
|
|
|
72
53
|
return { x: data.x, y: data.y, z: data.z, order: data.order };
|
|
73
54
|
}
|
|
74
55
|
}
|
|
75
|
-
export const euler = new EulerSerializer();
|
|
76
56
|
|
|
77
57
|
declare type ObjectData = {
|
|
78
58
|
node?: number;
|
|
@@ -107,16 +87,6 @@ class ObjectSerializer extends TypeSerializer {
|
|
|
107
87
|
console.warn(`Wrong usage of @serializable detected in your script \"${scriptname}\"\n\nIt looks like you used @serializable(Object3D) or @serializable(GameObject) for a prefab or scene reference which is exported to a separate glTF file.\n\nTo fix this please change your code to:\n\n@serializable(AssetReference)\n${context.path}! : AssetReference;\n\0`);
|
|
108
88
|
}
|
|
109
89
|
// ACTUALLY: this is already handled by the extension_utils where we resolve json pointers recursively
|
|
110
|
-
// if(data.startsWith("/nodes/")){
|
|
111
|
-
// const node = parseInt(data.substring("/nodes/".length));
|
|
112
|
-
// if (context.nodeToObject) {
|
|
113
|
-
// const res = context.nodeToObject[node];
|
|
114
|
-
// if (debugExtension)
|
|
115
|
-
// console.log("Deserialized object reference?", data, res, context?.nodeToObject);
|
|
116
|
-
// if (!res) console.warn("Did not find node: " + data, context.nodeToObject, context.object);
|
|
117
|
-
// return res;
|
|
118
|
-
// }
|
|
119
|
-
// }
|
|
120
90
|
return undefined;
|
|
121
91
|
}
|
|
122
92
|
|
|
@@ -166,7 +136,6 @@ class ObjectSerializer extends TypeSerializer {
|
|
|
166
136
|
return undefined;
|
|
167
137
|
}
|
|
168
138
|
}
|
|
169
|
-
export const objectSerializer = new ObjectSerializer();
|
|
170
139
|
|
|
171
140
|
|
|
172
141
|
class ComponentSerializer extends TypeSerializer {
|
|
@@ -241,7 +210,6 @@ class ComponentSerializer extends TypeSerializer {
|
|
|
241
210
|
}
|
|
242
211
|
}
|
|
243
212
|
}
|
|
244
|
-
export const componentSerializer = new ComponentSerializer();
|
|
245
213
|
|
|
246
214
|
|
|
247
215
|
declare class EventListData {
|
|
@@ -396,21 +364,12 @@ class EventListSerializer extends TypeSerializer {
|
|
|
396
364
|
// };
|
|
397
365
|
// }
|
|
398
366
|
}
|
|
399
|
-
export const eventListSerializer = new EventListSerializer();
|
|
400
367
|
|
|
401
368
|
|
|
402
369
|
/** Map<Clone, Original> texture. This is used for compressed textures (or when the GLTFLoader is cloning RenderTextures)
|
|
403
370
|
* It's a weak map so we don't have to worry about memory leaks
|
|
404
371
|
*/
|
|
405
372
|
const cloneOriginalMap = new WeakMap<Texture, Texture>();
|
|
406
|
-
const textureClone = Texture.prototype.clone;
|
|
407
|
-
Texture.prototype.clone = function () {
|
|
408
|
-
const clone = textureClone.call(this);
|
|
409
|
-
if (!cloneOriginalMap.has(clone)) {
|
|
410
|
-
cloneOriginalMap.set(clone, this);
|
|
411
|
-
}
|
|
412
|
-
return clone;
|
|
413
|
-
}
|
|
414
373
|
|
|
415
374
|
export class RenderTextureSerializer extends TypeSerializer {
|
|
416
375
|
constructor() {
|
|
@@ -452,7 +411,6 @@ export class RenderTextureSerializer extends TypeSerializer {
|
|
|
452
411
|
return undefined;
|
|
453
412
|
}
|
|
454
413
|
}
|
|
455
|
-
new RenderTextureSerializer();
|
|
456
414
|
|
|
457
415
|
|
|
458
416
|
export class UriSerializer extends TypeSerializer {
|
|
@@ -471,4 +429,35 @@ export class UriSerializer extends TypeSerializer {
|
|
|
471
429
|
return undefined;
|
|
472
430
|
}
|
|
473
431
|
}
|
|
474
|
-
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
// Module-level references used by EventListSerializer internally
|
|
435
|
+
export let colorSerializer: ColorSerializer;
|
|
436
|
+
export let objectSerializer: ObjectSerializer;
|
|
437
|
+
export let componentSerializer: ComponentSerializer;
|
|
438
|
+
export let eventListSerializer: EventListSerializer;
|
|
439
|
+
|
|
440
|
+
/** Register all builtin serializers and prototype patches.
|
|
441
|
+
* Must be called from {@link initEngine} so the registrations survive tree-shaking
|
|
442
|
+
* when the package declares `sideEffects: false`.
|
|
443
|
+
*/
|
|
444
|
+
export function initBuiltinSerializers() {
|
|
445
|
+
// Prototype patches
|
|
446
|
+
const textureClone = Texture.prototype.clone;
|
|
447
|
+
Texture.prototype.clone = function () {
|
|
448
|
+
const clone = textureClone.call(this);
|
|
449
|
+
if (!cloneOriginalMap.has(clone)) {
|
|
450
|
+
cloneOriginalMap.set(clone, this);
|
|
451
|
+
}
|
|
452
|
+
return clone;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Register all serializers
|
|
456
|
+
colorSerializer = new ColorSerializer();
|
|
457
|
+
new EulerSerializer();
|
|
458
|
+
objectSerializer = new ObjectSerializer();
|
|
459
|
+
componentSerializer = new ComponentSerializer();
|
|
460
|
+
eventListSerializer = new EventListSerializer();
|
|
461
|
+
new RenderTextureSerializer();
|
|
462
|
+
new UriSerializer();
|
|
463
|
+
}
|
|
@@ -3,8 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Covers both the global JSX namespace (Preact, SolidJS, Svelte, vanilla TS)
|
|
5
5
|
* and React's module-scoped JSX namespace (react-jsx / react-jsxdev transform).
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: This file must be a module (has a top-level import/export) so that
|
|
8
|
+
* `declare module "react"` is treated as a *module augmentation* (merging into
|
|
9
|
+
* the existing React types) rather than an *ambient module declaration* (which
|
|
10
|
+
* would shadow/replace @types/react).
|
|
6
11
|
*/
|
|
7
12
|
|
|
13
|
+
import type { NeedleEngineAttributes } from "./needle-engine.js";
|
|
14
|
+
|
|
8
15
|
interface NeedleButtonJSXAttributes extends Partial<Omit<HTMLElement, "style" | "children">> {
|
|
9
16
|
style?: Partial<CSSStyleDeclaration>;
|
|
10
17
|
ar?: boolean | string;
|
|
@@ -23,7 +30,7 @@ interface NeedleLogoElementJSXAttributes extends Partial<Omit<HTMLElement, "styl
|
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
interface NeedleElements {
|
|
26
|
-
"needle-engine":
|
|
33
|
+
"needle-engine": Partial<NeedleEngineAttributes>;
|
|
27
34
|
"needle-button": NeedleButtonJSXAttributes;
|
|
28
35
|
"needle-menu": NeedleMenuJSXAttributes;
|
|
29
36
|
"needle-logo-element": NeedleLogoElementJSXAttributes;
|
|
@@ -36,7 +43,7 @@ declare global {
|
|
|
36
43
|
}
|
|
37
44
|
}
|
|
38
45
|
|
|
39
|
-
// React module-scoped JSX namespace
|
|
46
|
+
// React module-scoped JSX namespace (module augmentation, not ambient declaration)
|
|
40
47
|
declare module "react" {
|
|
41
48
|
namespace JSX {
|
|
42
49
|
interface IntrinsicElements extends NeedleElements {}
|
|
@@ -1586,4 +1586,7 @@ class AnimatorControllerSerializator extends TypeSerializer {
|
|
|
1586
1586
|
return undefined;
|
|
1587
1587
|
}
|
|
1588
1588
|
}
|
|
1589
|
-
|
|
1589
|
+
/** @internal */
|
|
1590
|
+
export function initAnimatorControllerSerializer() {
|
|
1591
|
+
new AnimatorControllerSerializator(AnimatorController);
|
|
1592
|
+
}
|
|
@@ -401,12 +401,13 @@ export class Light extends Behaviour implements ILight {
|
|
|
401
401
|
else if (this.light.parent !== this.gameObject)
|
|
402
402
|
this.gameObject.add(this.light);
|
|
403
403
|
}
|
|
404
|
-
this.context.lights.
|
|
404
|
+
this.context.lights.push(this);
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
onDisable() {
|
|
408
408
|
if (debug) console.log("DISABLE LIGHT", this.name);
|
|
409
|
-
this.context.lights.
|
|
409
|
+
const index = this.context.lights.indexOf(this);
|
|
410
|
+
if (index !== -1) this.context.lights.splice(index, 1);
|
|
410
411
|
if (this.light) {
|
|
411
412
|
if (this.selfIsLight)
|
|
412
413
|
this.light.intensity = 0;
|
|
@@ -290,6 +290,8 @@ export class ReflectionProbe extends Behaviour {
|
|
|
290
290
|
const current = block.getOverride("envMap")?.value;
|
|
291
291
|
if (current === this.texture) {
|
|
292
292
|
block.removeOveride("envMap");
|
|
293
|
+
block.removeOveride("envMapRotation");
|
|
294
|
+
block.removeOveride("envMapIntensity");
|
|
293
295
|
}
|
|
294
296
|
}
|
|
295
297
|
}
|