@needle-tools/engine 4.16.0 → 4.16.1-next.ad85c25
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 +3 -0
- package/README.md +92 -46
- package/SKILL.md +25 -33
- package/dist/{needle-engine.bundle-mHgaFC2W.min.js → needle-engine.bundle-BH1CfP8u.min.js} +131 -131
- package/dist/{needle-engine.bundle-Cx8Qrpbp.js → needle-engine.bundle-CCwAJ9v_.js} +5386 -5356
- package/dist/{needle-engine.bundle-CXVjO2uF.umd.cjs → needle-engine.bundle-b3CRN4sk.umd.cjs} +121 -121
- package/dist/needle-engine.d.ts +16 -287
- package/dist/needle-engine.js +2 -2
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/engine_context.js +2 -0
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/webcomponents/logo-element.d.ts +6 -3
- package/lib/engine/webcomponents/logo-element.js +18 -0
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +10 -7
- package/lib/engine/webcomponents/needle menu/needle-menu.js +13 -2
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +4 -1
- package/lib/engine/webcomponents/needle-engine.js +22 -15
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.js +15 -3
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.d.ts +10 -3
- package/lib/engine-components/ReflectionProbe.js +34 -10
- package/lib/engine-components/ReflectionProbe.js.map +1 -1
- package/package.json +17 -9
- package/plugins/next/next.d.ts +8 -0
- package/plugins/next/next.js +7 -6
- package/plugins/types/userconfig.d.ts +4 -6
- package/plugins/vite/ai.d.ts +17 -0
- package/plugins/vite/ai.js +2 -2
- package/plugins/vite/alias.d.ts +8 -0
- package/plugins/vite/alias.js +5 -2
- package/plugins/vite/asap.d.ts +7 -0
- package/plugins/vite/asap.js +3 -3
- package/plugins/vite/build-pipeline.d.ts +15 -0
- package/plugins/vite/build-pipeline.js +5 -6
- package/plugins/vite/build.d.ts +7 -0
- package/plugins/vite/build.js +5 -2
- package/plugins/vite/buildinfo.d.ts +7 -0
- package/plugins/vite/buildinfo.js +4 -2
- package/plugins/vite/config.d.ts +13 -0
- package/plugins/vite/config.js +1 -1
- package/plugins/vite/copyfiles.d.ts +7 -0
- package/plugins/vite/copyfiles.js +4 -2
- package/plugins/vite/custom-element-data.d.ts +25 -0
- package/plugins/vite/custom-element-data.js +2 -1
- package/plugins/vite/defines.d.ts +10 -0
- package/plugins/vite/defines.js +4 -3
- package/plugins/vite/dependencies.d.ts +21 -0
- package/plugins/vite/dependencies.js +3 -1
- package/plugins/vite/dependency-watcher.d.ts +11 -0
- package/plugins/vite/dependency-watcher.js +2 -1
- package/plugins/vite/drop-client.d.ts +1 -0
- package/plugins/vite/drop.d.ts +7 -0
- package/plugins/vite/drop.js +4 -4
- package/plugins/vite/editor-connection.d.ts +8 -0
- package/plugins/vite/editor-connection.js +6 -2
- package/plugins/vite/facebook-instant-games.d.ts +7 -0
- package/plugins/vite/facebook-instant-games.js +4 -2
- package/plugins/vite/gzip.d.ts +6 -0
- package/plugins/vite/gzip.js +5 -0
- package/plugins/vite/imports-logger.d.ts +13 -0
- package/plugins/vite/imports-logger.js +2 -1
- package/plugins/vite/index.d.ts +54 -0
- package/plugins/vite/index.js +16 -15
- package/plugins/vite/license.d.ts +7 -0
- package/plugins/vite/license.js +6 -6
- package/plugins/vite/local-files-analysis.d.ts +95 -0
- package/plugins/vite/local-files-analysis.js +2 -1
- package/plugins/vite/local-files-core.d.ts +51 -0
- package/plugins/vite/local-files-core.js +2 -2
- package/plugins/vite/local-files-internals.d.ts +3 -0
- package/plugins/vite/local-files-utils.d.ts +77 -0
- package/plugins/vite/local-files.d.ts +2 -0
- package/plugins/vite/logger.d.ts +8 -0
- package/plugins/vite/logger.js +1 -1
- package/plugins/vite/logging.d.ts +31 -0
- package/plugins/vite/meta.d.ts +7 -0
- package/plugins/vite/meta.js +4 -3
- package/plugins/vite/needle-app.d.ts +7 -0
- package/plugins/vite/needle-app.js +1 -1
- package/plugins/vite/npm.d.ts +4 -0
- package/plugins/vite/npm.js +1 -1
- package/plugins/vite/peer.d.ts +7 -0
- package/plugins/vite/peer.js +3 -1
- package/plugins/vite/poster-client.d.ts +1 -0
- package/plugins/vite/poster.d.ts +8 -0
- package/plugins/vite/poster.js +5 -2
- package/plugins/vite/pwa.d.ts +7 -0
- package/plugins/vite/pwa.js +4 -4
- package/plugins/vite/reload-client.d.ts +1 -0
- package/plugins/vite/reload.d.ts +7 -0
- package/plugins/vite/reload.js +7 -6
- package/plugins/vite/server.d.ts +7 -0
- package/plugins/vite/server.js +5 -5
- package/plugins/vite/transform-codegen.d.ts +8 -0
- package/plugins/vite/transform-codegen.js +6 -4
- package/plugins/vite/transform.d.ts +5 -0
- package/plugins/vite/transform.js +1 -1
- package/plugins/vite/vite-4.4-hack.d.ts +8 -0
- package/plugins/vite/vite-4.4-hack.js +1 -1
- package/src/engine/engine_context.ts +1 -0
- package/src/engine/webcomponents/logo-element.ts +20 -3
- package/src/engine/webcomponents/needle menu/needle-menu.ts +22 -9
- package/src/engine/webcomponents/needle-engine.ts +42 -35
- package/src/engine/xr/NeedleXRSession.ts +16 -3
- package/src/engine-components/ReflectionProbe.ts +38 -11
- package/plugins/types/next.d.ts +0 -3
- package/plugins/types/vite.d.ts +0 -14
|
@@ -20,8 +20,13 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
20
20
|
return document.createElement(elementName) as NeedleLogoElement;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
private _didInitialize = false;
|
|
24
|
+
|
|
23
25
|
constructor() {
|
|
24
26
|
super();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private initializeDom() {
|
|
25
30
|
this._root = this.attachShadow({ mode: 'closed' });
|
|
26
31
|
const template = document.createElement('template');
|
|
27
32
|
template.innerHTML = `<style>
|
|
@@ -83,25 +88,37 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
83
88
|
this.addEventListener("click", () => {
|
|
84
89
|
globalThis.open("https://needle.tools", "_blank");
|
|
85
90
|
});
|
|
91
|
+
}
|
|
86
92
|
|
|
93
|
+
private ensureInitialized() {
|
|
94
|
+
if (!this._didInitialize) {
|
|
95
|
+
this._didInitialize = true;
|
|
96
|
+
this.initializeDom();
|
|
97
|
+
}
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
connectedCallback() {
|
|
101
|
+
this.ensureInitialized();
|
|
102
|
+
if (!this.wrapper) return;
|
|
90
103
|
this.wrapper.setAttribute("title", "Made with Needle Engine");
|
|
91
104
|
this.setAttribute("aria-label", "Needle Engine logo. Click to open the Needle Engine website.");
|
|
92
105
|
}
|
|
93
106
|
|
|
94
|
-
private
|
|
95
|
-
private
|
|
96
|
-
private
|
|
107
|
+
private _root!: ShadowRoot;
|
|
108
|
+
private wrapper!: HTMLDivElement;
|
|
109
|
+
private logoElement!: HTMLImageElement;
|
|
97
110
|
|
|
98
111
|
/** Show or hide the logo element (used by the menu) */
|
|
99
112
|
setLogoVisible(val: boolean) {
|
|
113
|
+
this.ensureInitialized();
|
|
114
|
+
if (!this.logoElement) return;
|
|
100
115
|
this.logoElement.style.display = val ? "block" : "none";
|
|
101
116
|
}
|
|
102
117
|
|
|
103
118
|
/** Switch the logo between full and compact versions */
|
|
104
119
|
setType(type: "full" | "compact") {
|
|
120
|
+
this.ensureInitialized();
|
|
121
|
+
if (!this.logoElement) return;
|
|
105
122
|
if (type === "full") {
|
|
106
123
|
this.logoElement.src = needleLogoSVG;
|
|
107
124
|
this.logoElement.classList.remove("with-text");
|
|
@@ -129,6 +129,7 @@ export class NeedleMenu {
|
|
|
129
129
|
|
|
130
130
|
constructor(context: Context) {
|
|
131
131
|
this._menu = NeedleMenuElement.getOrCreate(context.domElement, context);
|
|
132
|
+
this._menu.ensureInitialized();
|
|
132
133
|
this._context = context;
|
|
133
134
|
this._spatialMenu = new NeedleSpatialMenu(context, this._menu);
|
|
134
135
|
window.addEventListener("message", this.onPostMessage);
|
|
@@ -337,9 +338,13 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
337
338
|
|
|
338
339
|
private _domElement: HTMLElement | null = null;
|
|
339
340
|
private _context: Context | null = null;
|
|
341
|
+
private _didInitialize = false;
|
|
340
342
|
|
|
341
343
|
constructor() {
|
|
342
344
|
super();
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private initializeDom() {
|
|
343
348
|
|
|
344
349
|
const template = document.createElement('template');
|
|
345
350
|
// TODO: make host full size again and move the buttons to a wrapper so that we can later easily open e.g. foldouts/dropdowns / use the whole canvas space
|
|
@@ -793,7 +798,7 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
793
798
|
|
|
794
799
|
|
|
795
800
|
let context = this._context;
|
|
796
|
-
// we need to assign it in the timeout because the reference is set *after* the
|
|
801
|
+
// we need to assign it in the timeout because the reference is set *after* the element is initialized
|
|
797
802
|
setTimeout(() => context = this._context);
|
|
798
803
|
|
|
799
804
|
// watch changes
|
|
@@ -862,13 +867,21 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
862
867
|
}
|
|
863
868
|
}
|
|
864
869
|
|
|
870
|
+
ensureInitialized() {
|
|
871
|
+
if (!this._didInitialize) {
|
|
872
|
+
this._didInitialize = true;
|
|
873
|
+
this.initializeDom();
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
865
877
|
private _sizeChangeInterval;
|
|
866
878
|
|
|
867
879
|
connectedCallback() {
|
|
880
|
+
this.ensureInitialized();
|
|
868
881
|
window.addEventListener("resize", this.handleSizeChange);
|
|
869
882
|
this.handleMenuVisible();
|
|
870
883
|
this._sizeChangeInterval = setInterval(() => this.handleSizeChange(undefined, false), 5000);
|
|
871
|
-
// the dom element is set after
|
|
884
|
+
// the dom element is set after initialization runs
|
|
872
885
|
setTimeout(() => {
|
|
873
886
|
this._domElement?.addEventListener("resize", this.handleSizeChange);
|
|
874
887
|
this._domElement?.addEventListener("click", this.#onClick);
|
|
@@ -956,19 +969,19 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
956
969
|
|
|
957
970
|
// private _root: ShadowRoot | null = null;
|
|
958
971
|
/** @private root container element inside shadow DOM */
|
|
959
|
-
private
|
|
972
|
+
private root!: HTMLDivElement;
|
|
960
973
|
/** @private wraps the whole content (internal layout) */
|
|
961
|
-
private
|
|
974
|
+
private wrapper!: HTMLDivElement;
|
|
962
975
|
/** @private contains the buttons and dynamic elements */
|
|
963
|
-
private
|
|
976
|
+
private options!: HTMLDivElement;
|
|
964
977
|
/** @private contains options visible when in compact mode */
|
|
965
|
-
private
|
|
978
|
+
private optionsCompactMode!: HTMLDivElement;
|
|
966
979
|
/** @private contains the needle-logo html element */
|
|
967
|
-
private
|
|
980
|
+
private logoContainer!: HTMLDivElement;
|
|
968
981
|
/** @private compact menu button element */
|
|
969
|
-
private
|
|
982
|
+
private compactMenuButton!: HTMLButtonElement;
|
|
970
983
|
/** @private foldout container used in compact mode */
|
|
971
|
-
private
|
|
984
|
+
private foldout!: HTMLDivElement;
|
|
972
985
|
|
|
973
986
|
|
|
974
987
|
private readonly trackedElements: WeakSet<Node> = new WeakSet();
|
|
@@ -14,7 +14,7 @@ import { getParam } from "../engine_utils.js";
|
|
|
14
14
|
import { RGBAColor } from "../js-extensions/RGBAColor.js";
|
|
15
15
|
import { ensureFonts } from "./fonts.js";
|
|
16
16
|
import { arContainerClassName, AROverlayHandler } from "./needle-engine.ar-overlay.js";
|
|
17
|
-
import type { registerObservableAttribute} from "./needle-engine.extras.js";
|
|
17
|
+
import type { registerObservableAttribute } from "./needle-engine.extras.js";
|
|
18
18
|
import { calculateProgress01, EngineLoadingView, type ILoadingViewHandler } from "./needle-engine.loading.js";
|
|
19
19
|
|
|
20
20
|
declare global {
|
|
@@ -168,27 +168,19 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
168
168
|
*/
|
|
169
169
|
public get context() { return this._context; }
|
|
170
170
|
|
|
171
|
-
private _context
|
|
172
|
-
private _overlay_ar
|
|
171
|
+
private _context!: Context;
|
|
172
|
+
private _overlay_ar!: AROverlayHandler;
|
|
173
173
|
private _loadingProgress01: number = 0;
|
|
174
174
|
private _loadingView?: ILoadingViewHandler;
|
|
175
175
|
private _previousSrc: string | null | string[] = null;
|
|
176
176
|
/** @private set to true after <needle-engine> did load completely at least once. Set to false when < to false when <needle-engine> is removed from the document removed from the document */
|
|
177
177
|
private _didFullyLoad: boolean = false;
|
|
178
|
+
private _didInitialize = false;
|
|
178
179
|
|
|
179
180
|
constructor() {
|
|
180
181
|
super();
|
|
181
|
-
this._overlay_ar = new AROverlayHandler();
|
|
182
|
-
// TODO: do we want to rename this event?
|
|
183
|
-
this.addEventListener("ready", this.onReady);
|
|
184
|
-
|
|
185
|
-
ensureFonts();
|
|
186
|
-
|
|
187
182
|
this.attachShadow({ mode: 'open', delegatesFocus: true });
|
|
188
|
-
this.setAttribute("role", "application");
|
|
189
|
-
this.setAttribute("aria-label", "Needle Engine 3D scene");
|
|
190
183
|
const template = document.createElement('template');
|
|
191
|
-
// #region CSS
|
|
192
184
|
template.innerHTML = `<style>
|
|
193
185
|
@import url('https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wght@8..144,100..1000&display=swap');
|
|
194
186
|
|
|
@@ -254,7 +246,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
254
246
|
}
|
|
255
247
|
:host .quit-ar-button {
|
|
256
248
|
position: absolute;
|
|
257
|
-
|
|
249
|
+
/** top: env(titlebar-area-y); this doesnt work **/
|
|
258
250
|
top: 60px; /** camera access needs a bit more space **/
|
|
259
251
|
right: 20px;
|
|
260
252
|
z-index: 9999;
|
|
@@ -267,24 +259,36 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
267
259
|
<slot class="overlay-content" style="display: contents;"></slot>
|
|
268
260
|
</div>
|
|
269
261
|
`;
|
|
270
|
-
// #endregion
|
|
271
262
|
|
|
272
|
-
|
|
273
|
-
this.shadowRoot.appendChild(template.content.cloneNode(true));
|
|
263
|
+
this.shadowRoot!.appendChild(template.content.cloneNode(true));
|
|
274
264
|
|
|
275
|
-
|
|
265
|
+
// TODO: do we want to rename this event?
|
|
266
|
+
this.addEventListener("ready", this.onReady);
|
|
276
267
|
this.addEventListener("error", this.onError);
|
|
277
268
|
}
|
|
278
269
|
|
|
270
|
+
private ensureInitialized() {
|
|
271
|
+
if (!this._didInitialize) {
|
|
272
|
+
this._didInitialize = true;
|
|
273
|
+
this.initializeDom();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// #region Init DOM
|
|
278
|
+
private initializeDom() {
|
|
279
|
+
ensureFonts();
|
|
280
|
+
this.setAttribute("role", "application");
|
|
281
|
+
this.setAttribute("aria-label", "Needle Engine 3D scene");
|
|
282
|
+
}
|
|
283
|
+
|
|
279
284
|
|
|
280
285
|
/**
|
|
281
286
|
* @internal
|
|
282
287
|
*/
|
|
283
|
-
|
|
284
|
-
if (debug)
|
|
285
|
-
console.log("<needle-engine> connected");
|
|
286
|
-
}
|
|
288
|
+
connectedCallback() {
|
|
289
|
+
if (debug) console.log("<needle-engine> connected");
|
|
287
290
|
|
|
291
|
+
this.ensureInitialized();
|
|
288
292
|
this.setPublicKey();
|
|
289
293
|
this.setVersion();
|
|
290
294
|
|
|
@@ -293,9 +297,13 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
293
297
|
this.setAttribute("tabindex", "0");
|
|
294
298
|
|
|
295
299
|
|
|
300
|
+
this._overlay_ar = new AROverlayHandler();
|
|
301
|
+
this._context ??= new Context({ domElement: this }); // we might have one already if onLoad is running
|
|
296
302
|
this.addEventListener("xr-session-started", this.onXRSessionStarted);
|
|
297
303
|
this.onSetupDesktop();
|
|
298
304
|
|
|
305
|
+
|
|
306
|
+
|
|
299
307
|
if (!this.getAttribute("src")) {
|
|
300
308
|
const global = (globalThis as any)["needle:codegen_files"] as unknown as string;
|
|
301
309
|
if (debug) console.log("src is null, trying to load from globalThis[\"needle:codegen_files\"]", global);
|
|
@@ -442,6 +450,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
442
450
|
private async onLoad() {
|
|
443
451
|
|
|
444
452
|
if (!this.isConnected) return;
|
|
453
|
+
|
|
445
454
|
if (!this._context) {
|
|
446
455
|
if (debug) console.warn("Create new context");
|
|
447
456
|
this._context = new Context({ domElement: this });
|
|
@@ -476,7 +485,6 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
476
485
|
this.classList.add("loading");
|
|
477
486
|
|
|
478
487
|
|
|
479
|
-
|
|
480
488
|
// Loading start events
|
|
481
489
|
const allowOverridingDefaultLoading = hasCommercialLicense();
|
|
482
490
|
// default loading can be overriden by calling preventDefault in the onload start event
|
|
@@ -901,7 +909,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
901
909
|
setAttribute(name: 'ktx2DecoderPath', value: string): void;
|
|
902
910
|
/** Prevent Needle Engine context from being disposed when the element is removed from the DOM */
|
|
903
911
|
setAttribute(name: 'keep-alive', value: 'true' | 'false'): void;
|
|
904
|
-
|
|
912
|
+
|
|
905
913
|
/** @private Public key used for licensing and feature gating. */
|
|
906
914
|
setAttribute(name: 'public-key', value: string): void;
|
|
907
915
|
/** @private Engine version string — usually set by the build/runtime. */
|
|
@@ -909,7 +917,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
909
917
|
|
|
910
918
|
// LoadingAttributes
|
|
911
919
|
// ...
|
|
912
|
-
|
|
920
|
+
|
|
913
921
|
// SkyboxAttributes
|
|
914
922
|
/** URL to .exr, .hdr, .png, .jpg to be used as skybox */
|
|
915
923
|
setAttribute(name: 'background-image', value: string): void;
|
|
@@ -930,7 +938,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
930
938
|
* @example "background-color='#ff0000'" will set the background color to red.
|
|
931
939
|
*/
|
|
932
940
|
setAttribute(name: 'background-color', value: string): void;
|
|
933
|
-
|
|
941
|
+
|
|
934
942
|
// RenderingAttributes
|
|
935
943
|
/** Enable/disable renderer canvas transparency. */
|
|
936
944
|
setAttribute(name: 'transparent', value: 'true' | 'false'): void;
|
|
@@ -953,9 +961,9 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
953
961
|
setAttribute(name: "autoplay", value: 'true' | 'false'): void;
|
|
954
962
|
/** @private Used for switching the scene in SceneSwitcher */
|
|
955
963
|
setAttribute(name: 'scene', value: string): void;
|
|
956
|
-
|
|
964
|
+
|
|
957
965
|
// setAttribute(name: 'loadstart', value: string): void;
|
|
958
|
-
|
|
966
|
+
|
|
959
967
|
/** @private Experimental.*/
|
|
960
968
|
setAttribute(name: 'loading-blur', value: 'true' | 'false'): void;
|
|
961
969
|
/** @private */
|
|
@@ -968,9 +976,9 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
968
976
|
/** Generic typed setter for known Needle Engine attributes */
|
|
969
977
|
// Comment out to see errors inside NE for undocumented attributes
|
|
970
978
|
// setAttribute<T extends keyof NeedleEngineAttributes>(qualifiedName: T, value: NeedleEngineAttributes[T]): void;
|
|
971
|
-
|
|
979
|
+
|
|
972
980
|
setAttribute(qualifiedName: ({} & string), value: string): void;
|
|
973
|
-
|
|
981
|
+
|
|
974
982
|
// The ones we're using internally:
|
|
975
983
|
/*
|
|
976
984
|
setAttribute(name: "tabindex", value: string): void;
|
|
@@ -999,7 +1007,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
999
1007
|
getAttribute(name: 'ktx2DecoderPath'): string | null;
|
|
1000
1008
|
/** Prevent Needle Engine context from being disposed when the element is removed from the DOM */
|
|
1001
1009
|
getAttribute(name: 'keep-alive'): string | null;
|
|
1002
|
-
|
|
1010
|
+
|
|
1003
1011
|
/** @private Public key used for licensing and feature gating. */
|
|
1004
1012
|
getAttribute(name: 'public-key'): string | null;
|
|
1005
1013
|
/** @private Engine version string — usually set by the build/runtime. */
|
|
@@ -1070,13 +1078,13 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
1070
1078
|
/** Typed getter for known NeedleEngine attribute names; returns the typed shape declared in NeedleEngineAttributes or null. */
|
|
1071
1079
|
// getAttribute<T extends keyof NeedleEngineAttributes>(qualifiedName: T): NeedleEngineAttributes[T] | null;
|
|
1072
1080
|
getAttribute(qualifiedName: ({} & string)): string | null;
|
|
1073
|
-
|
|
1081
|
+
|
|
1074
1082
|
// The ones we're using interally:
|
|
1075
1083
|
/*
|
|
1076
1084
|
getAttribute(name: "autostart"): string | null;
|
|
1077
1085
|
getAttribute(name: "tabindex"): string | null;
|
|
1078
1086
|
*/
|
|
1079
|
-
|
|
1087
|
+
|
|
1080
1088
|
getAttribute(qualifiedName: string): string | null {
|
|
1081
1089
|
return super.getAttribute(qualifiedName);
|
|
1082
1090
|
}
|
|
@@ -1114,7 +1122,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
1114
1122
|
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
|
1115
1123
|
// This would be better but doesn't completely solve it
|
|
1116
1124
|
// addEventListener(type: ({} & string), listener: any, options?: boolean | AddEventListenerOptions): void;
|
|
1117
|
-
|
|
1125
|
+
|
|
1118
1126
|
// The ones we're using interally:
|
|
1119
1127
|
/*
|
|
1120
1128
|
addEventListener(type: "error", listener: (ev: ErrorEvent) => void, options?: boolean | AddEventListenerOptions): void;
|
|
@@ -1123,8 +1131,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
1123
1131
|
addEventListener(type: "drop", listener: (ev: DragEvent) => void, options?: boolean | AddEventListenerOptions): void;
|
|
1124
1132
|
addEventListener(type: "dragover", listener: (ev: DragEvent) => void, options?: boolean | AddEventListenerOptions): void;
|
|
1125
1133
|
*/
|
|
1126
|
-
addEventListener(type: string, listener: any, options?: boolean | AddEventListenerOptions): void
|
|
1127
|
-
{
|
|
1134
|
+
addEventListener(type: string, listener: any, options?: boolean | AddEventListenerOptions): void {
|
|
1128
1135
|
return super.addEventListener(type, listener as EventListenerOrEventListenerObject, options);
|
|
1129
1136
|
}
|
|
1130
1137
|
}
|
|
@@ -255,6 +255,7 @@ function handleAutoStart(value: string | null) {
|
|
|
255
255
|
// }
|
|
256
256
|
|
|
257
257
|
const $initialFov = Symbol("initial-fov");
|
|
258
|
+
const $initialNear = Symbol("initial-near");
|
|
258
259
|
|
|
259
260
|
/**
|
|
260
261
|
* This class manages an XRSession to provide helper methods and events. It provides easy access to the XRInputSources (controllers and hands)
|
|
@@ -1070,6 +1071,12 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1070
1071
|
this._originalCameraParent = this.context.mainCamera.parent;
|
|
1071
1072
|
if (this.context.mainCamera instanceof PerspectiveCamera) {
|
|
1072
1073
|
this.context.mainCamera[$initialFov] = this.context.mainCamera.fov;
|
|
1074
|
+
|
|
1075
|
+
// if (this.mode === "immersive-ar" && this.context.mainCamera.near > .1) {
|
|
1076
|
+
// console.log("[WebXR] Setting near plane to 0.1 for better AR experience (was " + this.context.mainCamera.near + "). The initial near plane will be restored when the session ends.");
|
|
1077
|
+
// this.context.mainCamera.near = 0.1;
|
|
1078
|
+
// this.context.mainCamera[$initialNear] = this.context.mainCamera.near;
|
|
1079
|
+
// }
|
|
1073
1080
|
}
|
|
1074
1081
|
}
|
|
1075
1082
|
|
|
@@ -1308,9 +1315,15 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1308
1315
|
setWorldScale(this.context.mainCamera, this._originalCameraWorldScale);
|
|
1309
1316
|
}
|
|
1310
1317
|
|
|
1311
|
-
if (this.context.mainCamera instanceof PerspectiveCamera
|
|
1312
|
-
|
|
1313
|
-
|
|
1318
|
+
if (this.context.mainCamera instanceof PerspectiveCamera) {
|
|
1319
|
+
if (this.context.mainCamera[$initialFov]) {
|
|
1320
|
+
this.context.mainCamera.fov = this.context.mainCamera[$initialFov]!;
|
|
1321
|
+
this.context.mainCamera[$initialFov] = 0;
|
|
1322
|
+
}
|
|
1323
|
+
if (this.context.mainCamera[$initialNear]) {
|
|
1324
|
+
this.context.mainCamera.near = this.context.mainCamera[$initialNear]!;
|
|
1325
|
+
this.context.mainCamera[$initialNear] = 0;
|
|
1326
|
+
}
|
|
1314
1327
|
}
|
|
1315
1328
|
}
|
|
1316
1329
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CubeTexture, EquirectangularReflectionMapping, LinearSRGBColorSpace, Material, Object3D, Texture, Vector3 } from "three";
|
|
1
|
+
import { Box3, Color, CubeTexture, EquirectangularReflectionMapping, LinearSRGBColorSpace, LineSegments, Material, Object3D, Quaternion, Texture, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { MaterialPropertyBlock } from "../engine/engine_materialpropertyblock.js";
|
|
4
4
|
import { loadPMREM } from "../engine/engine_pmrem.js";
|
|
@@ -8,6 +8,8 @@ import { getParam, resolveUrl } from "../engine/engine_utils.js";
|
|
|
8
8
|
import { BoxHelperComponent } from "./BoxHelperComponent.js";
|
|
9
9
|
import { Behaviour } from "./Component.js";
|
|
10
10
|
import { EventList } from "./EventList.js";
|
|
11
|
+
import { getBoundingBox, getWorldPosition } from "../engine/engine_three_utils.js";
|
|
12
|
+
import { CreateWireCube } from "../engine/engine_gizmos.js";
|
|
11
13
|
|
|
12
14
|
export const debug = getParam("debugreflectionprobe");
|
|
13
15
|
const disable = getParam("noreflectionprobe");
|
|
@@ -40,8 +42,11 @@ const $reflectionProbeKey = Symbol("reflectionProbeKey");
|
|
|
40
42
|
export class ReflectionProbe extends Behaviour {
|
|
41
43
|
|
|
42
44
|
private static _probes: Map<Context, ReflectionProbe[]> = new Map();
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
/** The bounding box for this component */
|
|
46
|
+
private box: Box3 | null = null;
|
|
47
|
+
private static testBox: Box3 = new Box3();
|
|
48
|
+
private static _identityRotation: Quaternion = new Quaternion();
|
|
49
|
+
|
|
45
50
|
/**
|
|
46
51
|
* Checks if the given material is currently using a reflection probe. This is determined by checking for an override on the material's "envMap" property, which is set by the Renderer component when applying a reflection probe.
|
|
47
52
|
*/
|
|
@@ -151,23 +156,33 @@ export class ReflectionProbe extends Behaviour {
|
|
|
151
156
|
* Defines the center and size of the reflection probe's influence area.
|
|
152
157
|
*/
|
|
153
158
|
@serializable(Vector3)
|
|
154
|
-
center
|
|
159
|
+
center: Vector3 = new Vector3();
|
|
155
160
|
|
|
156
161
|
/**
|
|
157
162
|
* Defines the size of the reflection probe's influence area. Objects within this box will be affected by the probe's reflections.
|
|
158
163
|
*/
|
|
159
164
|
@serializable(Vector3)
|
|
160
|
-
size
|
|
165
|
+
size: Vector3 = new Vector3(1, 1, 1);
|
|
161
166
|
|
|
162
167
|
/**
|
|
163
168
|
* Workaround for lightmap. Compensates for the fact that lightmaps are pre-multiplied by intensity, while reflection probes are not. This means that if you use both lightmaps and reflection probes, you may need to adjust this value to get the correct balance between them. The default value of `Math.PI` is a good starting point for most cases, but you may need to tweak it based on your specific lighting setup and artistic needs.
|
|
164
169
|
*/
|
|
165
170
|
__lightmapIntensityScale: boolean = true;
|
|
166
171
|
|
|
167
|
-
private _boxHelper?: BoxHelperComponent;
|
|
168
172
|
|
|
169
173
|
private isInBox(obj: Object3D) {
|
|
170
|
-
|
|
174
|
+
|
|
175
|
+
this.box ??= new Box3();
|
|
176
|
+
this.box!.setFromCenterAndSize(this.gameObject.worldPosition.add(this.center), this.gameObject.worldScale.multiply(this.size));
|
|
177
|
+
|
|
178
|
+
getBoundingBox([obj], undefined, undefined, ReflectionProbe.testBox);
|
|
179
|
+
|
|
180
|
+
if (ReflectionProbe.testBox.isEmpty()) {
|
|
181
|
+
return this.box.containsPoint(obj.worldPosition);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
return this.box?.intersectsBox(ReflectionProbe.testBox);
|
|
185
|
+
}
|
|
171
186
|
}
|
|
172
187
|
|
|
173
188
|
constructor() {
|
|
@@ -178,12 +193,15 @@ export class ReflectionProbe extends Behaviour {
|
|
|
178
193
|
ReflectionProbe._probes.get(this.context)?.push(this);
|
|
179
194
|
}
|
|
180
195
|
|
|
196
|
+
private _gizmo: LineSegments | null = null;
|
|
197
|
+
private _color: Color | null = null;
|
|
198
|
+
|
|
181
199
|
/** @internal */
|
|
182
200
|
awake() {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
201
|
+
if (debug) {
|
|
202
|
+
this._gizmo = CreateWireCube(0x555500);
|
|
203
|
+
this.gameObject.add(this._gizmo);
|
|
204
|
+
}
|
|
187
205
|
|
|
188
206
|
if (this._texture) {
|
|
189
207
|
this._texture.mapping = EquirectangularReflectionMapping;
|
|
@@ -192,6 +210,15 @@ export class ReflectionProbe extends Behaviour {
|
|
|
192
210
|
}
|
|
193
211
|
}
|
|
194
212
|
|
|
213
|
+
/** @internal */
|
|
214
|
+
update(): void {
|
|
215
|
+
if (this._gizmo) {
|
|
216
|
+
if (this.center) this._gizmo.position.copy(this.center);
|
|
217
|
+
if (this.size) this._gizmo.scale.copy(this.size);
|
|
218
|
+
this._gizmo.worldQuaternion = ReflectionProbe._identityRotation;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
195
222
|
/** @internal */
|
|
196
223
|
onEnable(): void {
|
|
197
224
|
ReflectionProbe.onEnabled?.invoke(this);
|
package/plugins/types/next.d.ts
DELETED
package/plugins/types/vite.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { needleConfig, needleMeta } from "./needleConfig.d.ts";
|
|
2
|
-
import { userSettings } from "./userconfig.d.ts";
|
|
3
|
-
|
|
4
|
-
export declare function needlePlugins(command: import("vite").ConfigEnv["command"], meta?: needleMeta | null, userSettings?: userSettings): Promise<any>;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Loads the generated needle meta file
|
|
8
|
-
*/
|
|
9
|
-
export declare function loadConfig(path: string | null = null): Promise<needleMeta | null>;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Returns true if the project is configured to use gzip compression
|
|
13
|
-
*/
|
|
14
|
-
export declare function useGzip(config?: needleConfig): boolean;
|