@needle-tools/engine 5.1.0-alpha.1 → 5.1.0-canary.30cc545
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/components.needle.json +1 -1
- package/dist/{gltf-progressive-DJBMx-zB.umd.cjs → gltf-progressive-BmblPzFj.umd.cjs} +4 -4
- package/dist/{gltf-progressive-BryRjllq.min.js → gltf-progressive-CN_mbb66.min.js} +2 -2
- package/dist/{gltf-progressive-Cl167Vjx.js → gltf-progressive-DUlhxdv4.js} +5 -2
- package/dist/{needle-engine.bundle-DzVx9Z8D.umd.cjs → needle-engine.bundle-BMlLSACE.umd.cjs} +159 -159
- package/dist/{needle-engine.bundle-CiYtOO2O.min.js → needle-engine.bundle-BXPPQRer.min.js} +157 -157
- package/dist/{needle-engine.bundle-BGyKqxBH.js → needle-engine.bundle-d_9mSxN4.js} +6730 -6585
- package/dist/needle-engine.d.ts +91 -12
- package/dist/needle-engine.js +172 -170
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-B_9sKVU7.min.js → postprocessing-B571qGWR.min.js} +34 -34
- package/dist/{postprocessing-WDc9WwI3.js → postprocessing-CfrLAbLX.js} +0 -1
- package/dist/{postprocessing-B2wb6pzI.umd.cjs → postprocessing-CiGkAeM9.umd.cjs} +17 -17
- package/dist/{vendor-CAcsI0eU.js → vendor-BFrMaK9q.js} +8983 -9136
- package/dist/vendor-CJmyOrCq.min.js +1116 -0
- package/dist/vendor-DkMW3WY4.umd.cjs +1116 -0
- package/lib/engine/api.d.ts +12 -0
- package/lib/engine/api.js +2 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug_environment.js +1 -1
- package/lib/engine/debug/debug_environment.js.map +1 -1
- package/lib/engine/engine_application.js +8 -6
- package/lib/engine/engine_application.js.map +1 -1
- package/lib/engine/engine_constants.js +6 -0
- package/lib/engine/engine_constants.js.map +1 -1
- package/lib/engine/engine_context.d.ts +25 -0
- package/lib/engine/engine_context.js +27 -0
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_context_registry.js +1 -1
- package/lib/engine/engine_context_registry.js.map +1 -1
- package/lib/engine/engine_input.d.ts +3 -2
- package/lib/engine/engine_input.js +3 -2
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_license.js +11 -9
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_networking_blob.d.ts +1 -1
- package/lib/engine/engine_networking_blob.js +5 -11
- package/lib/engine/engine_networking_blob.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +0 -1
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_pmrem.js +2 -2
- package/lib/engine/engine_pmrem.js.map +1 -1
- package/lib/engine/engine_scenedata.d.ts +36 -0
- package/lib/engine/engine_scenedata.js +111 -0
- package/lib/engine/engine_scenedata.js.map +1 -0
- package/lib/engine/engine_ssr.d.ts +16 -0
- package/lib/engine/engine_ssr.js +38 -0
- package/lib/engine/engine_ssr.js.map +1 -0
- package/lib/engine/engine_three_utils.d.ts +14 -7
- package/lib/engine/engine_three_utils.js +14 -7
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine/engine_utils.js +2 -0
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/engine_utils_hash.d.ts +9 -0
- package/lib/engine/engine_utils_hash.js +112 -0
- package/lib/engine/engine_utils_hash.js.map +1 -0
- package/lib/engine/webcomponents/logo-element.d.ts +2 -1
- package/lib/engine/webcomponents/logo-element.js +2 -1
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +2 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +2 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-button.d.ts +2 -1
- package/lib/engine/webcomponents/needle-button.js +2 -1
- package/lib/engine/webcomponents/needle-button.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +2 -1
- package/lib/engine/webcomponents/needle-engine.js +2 -1
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.js +1 -1
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/RigidBody.js +3 -3
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +2 -0
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/BloomEffect.d.ts +1 -1
- package/lib/engine-components/postprocessing/Effects/Sharpening.js +1 -2
- package/lib/engine-components/postprocessing/Effects/Sharpening.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.js +5 -6
- package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +0 -1
- package/lib/engine-components/web/ScrollFollow.js +3 -2
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/package.json +6 -5
- package/plugins/dts-generator/dts.codegen.js +129 -0
- package/plugins/dts-generator/dts.scan.js +71 -0
- package/plugins/dts-generator/dts.writer.js +59 -0
- package/plugins/dts-generator/glb.discovery.js +162 -0
- package/plugins/dts-generator/glb.extractor.js +175 -0
- package/plugins/dts-generator/glb.reader.js +114 -0
- package/plugins/dts-generator/index.js +36 -0
- package/plugins/dts-generator/manifest.types.js +174 -0
- package/plugins/types/index.d.ts +2 -1
- package/plugins/types/needle-bindings.d.ts +19 -0
- package/plugins/types/userconfig.d.ts +9 -2
- package/plugins/vite/dts-generator.d.ts +7 -0
- package/plugins/vite/dts-generator.js +157 -0
- package/plugins/vite/index.d.ts +1 -0
- package/plugins/vite/index.js +4 -0
- package/plugins/vite/logging.js +2 -2
- package/plugins/vite/reload.js +2 -1
- package/src/engine/api.ts +15 -1
- package/src/engine/debug/debug_environment.ts +1 -1
- package/src/engine/engine_application.ts +8 -6
- package/src/engine/engine_constants.ts +11 -6
- package/src/engine/engine_context.ts +29 -0
- package/src/engine/engine_context_registry.ts +1 -1
- package/src/engine/engine_input.ts +3 -2
- package/src/engine/engine_license.ts +11 -9
- package/src/engine/engine_networking_blob.ts +5 -11
- package/src/engine/engine_physics_rapier.ts +0 -3
- package/src/engine/engine_pmrem.ts +3 -3
- package/src/engine/engine_scenedata.ts +110 -0
- package/src/engine/engine_ssr.ts +45 -0
- package/src/engine/engine_three_utils.ts +15 -7
- package/src/engine/engine_utils.ts +1 -0
- package/src/engine/engine_utils_hash.ts +65 -0
- package/src/engine/webcomponents/logo-element.ts +2 -1
- package/src/engine/webcomponents/needle menu/needle-menu.ts +2 -1
- package/src/engine/webcomponents/needle-button.ts +2 -1
- package/src/engine/webcomponents/needle-engine.ts +2 -1
- package/src/engine/xr/NeedleXRSession.ts +1 -1
- package/src/engine-components/RigidBody.ts +3 -3
- package/src/engine-components/SceneSwitcher.ts +1 -0
- package/src/engine-components/postprocessing/Effects/BloomEffect.ts +1 -1
- package/src/engine-components/postprocessing/Effects/Sharpening.ts +1 -2
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +4 -8
- package/src/engine-components/web/ScrollFollow.ts +2 -2
- package/src/vite-env.d.ts +16 -0
- package/dist/vendor-CEM38hLE.umd.cjs +0 -1116
- package/dist/vendor-HRlxIBga.min.js +0 -1116
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import * as _md5 from "md5";
|
|
2
|
-
// CJS interop: md5 may appear as { default: fn } or fn depending on bundler
|
|
3
|
-
const md5 = typeof _md5 === "function" ? _md5 : (_md5 as any).default;
|
|
4
1
|
import { FileLoader } from "three";
|
|
5
2
|
|
|
6
3
|
import { showBalloonWarning } from "./debug/index.js";
|
|
7
4
|
import { hasCommercialLicense } from "./engine_license.js";
|
|
8
5
|
import { delay } from "./engine_utils.js";
|
|
6
|
+
import { md5Hex, md5AsBytes, sha256Base64 } from "./engine_utils_hash.js";
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
export namespace BlobStorage {
|
|
@@ -22,21 +20,17 @@ export namespace BlobStorage {
|
|
|
22
20
|
/**
|
|
23
21
|
* Generates an md5 hash from a given buffer
|
|
24
22
|
* @param buffer The buffer to hash
|
|
25
|
-
* @returns The md5 hash
|
|
23
|
+
* @returns The md5 hash as a hex string
|
|
26
24
|
*/
|
|
27
25
|
export function hashMD5(buffer: ArrayBuffer): string {
|
|
28
|
-
return
|
|
26
|
+
return md5Hex(new Uint8Array(buffer));
|
|
29
27
|
}
|
|
30
28
|
export function hashMD5_Base64(buffer: ArrayBuffer): string {
|
|
31
|
-
const bytes =
|
|
29
|
+
const bytes = md5AsBytes(new Uint8Array(buffer));
|
|
32
30
|
return btoa(String.fromCharCode(...bytes));
|
|
33
31
|
}
|
|
34
32
|
export function hashSha256(buffer: ArrayBuffer): Promise<string> {
|
|
35
|
-
|
|
36
|
-
const hash = crypto.subtle.digest('SHA-256', bytes).then(res => {
|
|
37
|
-
return btoa(String.fromCharCode(...new Uint8Array(res)));
|
|
38
|
-
})
|
|
39
|
-
return hash;
|
|
33
|
+
return sha256Base64(buffer);
|
|
40
34
|
}
|
|
41
35
|
|
|
42
36
|
export type Upload_Result = {
|
|
@@ -44,9 +44,6 @@ const $bodyKey = Symbol("physics body");
|
|
|
44
44
|
const $colliderRigidbody = Symbol("rigidbody");
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
declare const NEEDLE_USE_RAPIER: boolean;
|
|
48
|
-
globalThis["NEEDLE_USE_RAPIER"] = globalThis["NEEDLE_USE_RAPIER"] !== undefined ? globalThis["NEEDLE_USE_RAPIER"] : true;
|
|
49
|
-
|
|
50
47
|
/** Register the Rapier physics backend. Called from {@link initEngine}
|
|
51
48
|
* to ensure it runs regardless of tree-shaking. */
|
|
52
49
|
export function initPhysics() {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createLoaders } from "@needle-tools/gltf-progressive";
|
|
2
2
|
import { CubeUVReflectionMapping, EquirectangularRefractionMapping, SRGBColorSpace, Texture, TextureLoader, WebGLRenderer } from "three";
|
|
3
|
-
import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader";
|
|
4
|
-
import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader";
|
|
5
|
-
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
|
|
3
|
+
import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader.js";
|
|
4
|
+
import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
5
|
+
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
|
|
6
6
|
|
|
7
7
|
const running: Map<string, Promise<Texture | null>> = new Map();
|
|
8
8
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { SceneData } from "needle:bindings";
|
|
2
|
+
import type { IContext } from "./engine_types.js";
|
|
3
|
+
import { getComponent } from "./engine_components.js";
|
|
4
|
+
import { TypeStore } from "./engine_typestore.js";
|
|
5
|
+
import { isDevEnvironment } from "./debug/index.js";
|
|
6
|
+
import { ContextRegistry } from "./engine_context_registry.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Global proxy for the primary Needle Engine context.
|
|
10
|
+
* Resolves lazily on property access via `ContextRegistry.Current` —
|
|
11
|
+
* safe to import at module level, including in SSR environments
|
|
12
|
+
* (returns a silent error proxy when no context is active).
|
|
13
|
+
*
|
|
14
|
+
* Use this outside of Needle component lifecycle (e.g. in Svelte/React/Vue
|
|
15
|
+
* components, button handlers, or vanilla JS) instead of threading `ctx` around.
|
|
16
|
+
*
|
|
17
|
+
* For multiple `<needle-engine>` elements on the same page, use `ctx` directly.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { needle } from "@needle-tools/engine";
|
|
21
|
+
* button.onclick = () => {
|
|
22
|
+
* needle.sceneData.Camera.OrbitControls.autoRotate = true;
|
|
23
|
+
* };
|
|
24
|
+
*/
|
|
25
|
+
export const needle: IContext = new Proxy({} as IContext, {
|
|
26
|
+
get(_target, prop: string) {
|
|
27
|
+
if (prop === "then") return undefined; // not a Promise
|
|
28
|
+
const ctx = ContextRegistry.Current;
|
|
29
|
+
if (!ctx) {
|
|
30
|
+
const fn = isDevEnvironment() ? console.error : console.warn;
|
|
31
|
+
fn(`[needle] needle.${prop} accessed before scene started`);
|
|
32
|
+
return makeErrorProxy(`needle not ready — scene hasn't started yet`);
|
|
33
|
+
}
|
|
34
|
+
const val = (ctx as any)[prop];
|
|
35
|
+
return typeof val === "function" ? val.bind(ctx) : val;
|
|
36
|
+
},
|
|
37
|
+
set(_target, prop: string, value: unknown) {
|
|
38
|
+
const ctx = ContextRegistry.Current;
|
|
39
|
+
if (!ctx) {
|
|
40
|
+
const fn = isDevEnvironment() ? console.error : console.warn;
|
|
41
|
+
fn(`[needle] needle.${prop} set before scene started`);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
(ctx as any)[prop] = value;
|
|
45
|
+
return true;
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const cache = new WeakMap<IContext, SceneData>();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Returns a proxy that silently absorbs any property get/set and logs a
|
|
53
|
+
* developer-friendly warning. Used when a node or component lookup fails so
|
|
54
|
+
* that chained access like `ctx.sceneData.Foo.Bar.baz = 1` never throws.
|
|
55
|
+
*/
|
|
56
|
+
function makeErrorProxy(message: string): object {
|
|
57
|
+
const handler: ProxyHandler<object> = {
|
|
58
|
+
get(_t, prop: string) {
|
|
59
|
+
if (prop === "then") return undefined; // not a Promise
|
|
60
|
+
const fn = isDevEnvironment() ? console.error : console.warn;
|
|
61
|
+
fn(`[SceneData] ${message}`);
|
|
62
|
+
return makeErrorProxy(message);
|
|
63
|
+
},
|
|
64
|
+
set(_t, prop: string) {
|
|
65
|
+
const fn = isDevEnvironment() ? console.error : console.warn;
|
|
66
|
+
fn(`[SceneData] ${message} (tried to set "${prop}")`);
|
|
67
|
+
return true; // suppress TypeError
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
return new Proxy({}, handler);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns a lazily-resolved proxy typed as {@link SceneData}.
|
|
75
|
+
* The proxy is cached per context — each context gets exactly one instance.
|
|
76
|
+
*
|
|
77
|
+
* Accessing a property traverses the scene graph on demand:
|
|
78
|
+
* - First level → find Object3D by node name
|
|
79
|
+
* - Second level → getComponent by component name (via TypeStore)
|
|
80
|
+
* - Third level → read/write a field on the real component instance
|
|
81
|
+
*
|
|
82
|
+
* If a node or component is not found, property accesses log a warning
|
|
83
|
+
* instead of throwing, so chained access never crashes.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ctx.sceneData.Camera.OrbitControls.autoRotate = true;
|
|
87
|
+
*/
|
|
88
|
+
export function getSceneData(ctx: IContext): SceneData {
|
|
89
|
+
let proxy = cache.get(ctx);
|
|
90
|
+
if (!proxy) {
|
|
91
|
+
proxy = new Proxy({} as SceneData, {
|
|
92
|
+
get(_target, nodeName: string) {
|
|
93
|
+
return new Proxy({}, {
|
|
94
|
+
get(_target, compName: string) {
|
|
95
|
+
const node = ctx.scene.getObjectByName(nodeName) ?? null;
|
|
96
|
+
if (!node) return makeErrorProxy(`Node "${nodeName}" not found in scene`);
|
|
97
|
+
if (compName === "$node") return node;
|
|
98
|
+
const ctor = TypeStore.get(compName);
|
|
99
|
+
if (!ctor) return makeErrorProxy(`Component type "${compName}" not registered (node "${nodeName}")`);
|
|
100
|
+
const comp = getComponent(node, ctor);
|
|
101
|
+
if (!comp) return makeErrorProxy(`Component "${compName}" not found on node "${nodeName}"`);
|
|
102
|
+
return comp;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
cache.set(ctx, proxy);
|
|
108
|
+
}
|
|
109
|
+
return proxy;
|
|
110
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR-safe base classes for browser globals that are not available in Node/SSR environments.
|
|
3
|
+
*
|
|
4
|
+
* Use these instead of extending browser globals directly so that class definitions
|
|
5
|
+
* do not throw a ReferenceError at module evaluation time in SSR/Node contexts
|
|
6
|
+
* (SvelteKit, Next.js, etc.).
|
|
7
|
+
*
|
|
8
|
+
* In browser environments each constant is the real global; in SSR it falls back
|
|
9
|
+
* to a plain empty class so that `class Foo extends HTMLElementBase` is valid.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/** SSR-safe base class for web components. */
|
|
14
|
+
export const HTMLElementBase: typeof HTMLElement =
|
|
15
|
+
typeof HTMLElement !== "undefined" ? HTMLElement : (class { } as unknown as typeof HTMLElement);
|
|
16
|
+
|
|
17
|
+
/** SSR-safe base class for pointer events. */
|
|
18
|
+
export const PointerEventBase: typeof PointerEvent =
|
|
19
|
+
typeof PointerEvent !== "undefined" ? PointerEvent : (class { } as unknown as typeof PointerEvent);
|
|
20
|
+
|
|
21
|
+
/** SSR-safe base class for keyboard events. */
|
|
22
|
+
export const KeyboardEventBase: typeof KeyboardEvent =
|
|
23
|
+
typeof KeyboardEvent !== "undefined" ? KeyboardEvent : (class { } as unknown as typeof KeyboardEvent);
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// #region minimal polyfills
|
|
29
|
+
// Three.js FileLoader uses ProgressEvent in fetch stream callbacks.
|
|
30
|
+
// It doesn't exist in Node — install a minimal stub so SSR doesn't crash.
|
|
31
|
+
if (typeof globalThis.ProgressEvent === "undefined") {
|
|
32
|
+
(globalThis as any).ProgressEvent = class ProgressEvent {
|
|
33
|
+
readonly type: string;
|
|
34
|
+
readonly lengthComputable: boolean;
|
|
35
|
+
readonly loaded: number;
|
|
36
|
+
readonly total: number;
|
|
37
|
+
constructor(type: string, init?: { lengthComputable?: boolean; loaded?: number; total?: number }) {
|
|
38
|
+
this.type = type;
|
|
39
|
+
this.lengthComputable = init?.lengthComputable ?? false;
|
|
40
|
+
this.loaded = init?.loaded ?? 0;
|
|
41
|
+
this.total = init?.total ?? 0;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// #endregion
|
|
@@ -493,13 +493,21 @@ void main(){
|
|
|
493
493
|
* Utility class to perform various graphics operations like copying textures to canvas
|
|
494
494
|
*/
|
|
495
495
|
export class Graphics {
|
|
496
|
-
private static
|
|
497
|
-
private static
|
|
498
|
-
private static
|
|
499
|
-
private static
|
|
500
|
-
private static
|
|
501
|
-
private static
|
|
502
|
-
private static
|
|
496
|
+
private static _planeGeometry: PlaneGeometry | undefined;
|
|
497
|
+
private static _renderer: WebGLRenderer | undefined;
|
|
498
|
+
private static _perspectiveCam: PerspectiveCamera | undefined;
|
|
499
|
+
private static _orthographicCam: OrthographicCamera | undefined;
|
|
500
|
+
private static _scene: Scene | undefined;
|
|
501
|
+
private static _blitMaterial: BlitMaterial | undefined;
|
|
502
|
+
private static _mesh: Mesh | undefined;
|
|
503
|
+
|
|
504
|
+
private static get planeGeometry() { return this._planeGeometry ??= new PlaneGeometry(2, 2, 1, 1); }
|
|
505
|
+
private static get renderer() { return this._renderer ??= new WebGLRenderer({ antialias: false, alpha: true }); }
|
|
506
|
+
private static get perspectiveCam() { return this._perspectiveCam ??= new PerspectiveCamera(); }
|
|
507
|
+
private static get orthographicCam() { return this._orthographicCam ??= new OrthographicCamera(); }
|
|
508
|
+
private static get scene() { return this._scene ??= new Scene(); }
|
|
509
|
+
private static get blitMaterial() { return this._blitMaterial ??= new BlitMaterial(); }
|
|
510
|
+
private static get mesh() { return this._mesh ??= new Mesh(Graphics.planeGeometry, Graphics.blitMaterial); }
|
|
503
511
|
|
|
504
512
|
|
|
505
513
|
/**
|
|
@@ -597,6 +597,7 @@ export namespace DeviceUtilities {
|
|
|
597
597
|
/** @returns `true` for MacOS or Windows devices. `false` for Hololens and other headsets. */
|
|
598
598
|
export function isDesktop() {
|
|
599
599
|
if (_isDesktop !== undefined) return _isDesktop;
|
|
600
|
+
if (typeof window === "undefined") return _isDesktop = false;
|
|
600
601
|
const ua = window.navigator.userAgent;
|
|
601
602
|
const standalone = /Windows|MacOS|Mac OS/.test(ua);
|
|
602
603
|
const isHololens = /Windows NT/.test(ua) && /Edg/.test(ua) && !/Win64/.test(ua);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-JS hashing utilities — no external dependencies, works in browser and Node/SSR.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// MD5 based on the public-domain RSA Data Security MD5 algorithm.
|
|
6
|
+
function md5Bytes(input: Uint8Array): number[] {
|
|
7
|
+
function safeAdd(x: number, y: number) { const lsw = (x & 0xffff) + (y & 0xffff); return ((x >> 16) + (y >> 16) + (lsw >> 16)) << 16 | lsw & 0xffff; }
|
|
8
|
+
function bitRotateLeft(num: number, cnt: number) { return num << cnt | num >>> 32 - cnt; }
|
|
9
|
+
function md5cmn(q: number, a: number, b: number, x: number, s: number, t: number) { return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); }
|
|
10
|
+
function md5ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { return md5cmn(b & c | ~b & d, a, b, x, s, t); }
|
|
11
|
+
function md5gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { return md5cmn(b & d | c & ~d, a, b, x, s, t); }
|
|
12
|
+
function md5hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { return md5cmn(b ^ c ^ d, a, b, x, s, t); }
|
|
13
|
+
function md5ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { return md5cmn(c ^ (b | ~d), a, b, x, s, t); }
|
|
14
|
+
|
|
15
|
+
const len8 = input.length;
|
|
16
|
+
const padded = new Uint8Array((Math.ceil((len8 + 9) / 64) * 64));
|
|
17
|
+
padded.set(input);
|
|
18
|
+
padded[len8] = 0x80;
|
|
19
|
+
const view = new DataView(padded.buffer);
|
|
20
|
+
view.setUint32(padded.length - 8, len8 << 3, true);
|
|
21
|
+
view.setUint32(padded.length - 4, (len8 / 0x20000000) | 0, true);
|
|
22
|
+
|
|
23
|
+
let a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476;
|
|
24
|
+
for (let i = 0; i < padded.length >> 2; i += 16) {
|
|
25
|
+
const M = (j: number) => view.getInt32((i + j) * 4, true);
|
|
26
|
+
const [oa, ob, oc, od] = [a, b, c, d];
|
|
27
|
+
a = md5ff(a,b,c,d,M(0),7,-680876936); d=md5ff(d,a,b,c,M(1),12,-389564586); c=md5ff(c,d,a,b,M(2),17,606105819); b=md5ff(b,c,d,a,M(3),22,-1044525330);
|
|
28
|
+
a=md5ff(a,b,c,d,M(4),7,-176418897); d=md5ff(d,a,b,c,M(5),12,1200080426); c=md5ff(c,d,a,b,M(6),17,-1473231341); b=md5ff(b,c,d,a,M(7),22,-45705983);
|
|
29
|
+
a=md5ff(a,b,c,d,M(8),7,1770035416); d=md5ff(d,a,b,c,M(9),12,-1958414417); c=md5ff(c,d,a,b,M(10),17,-42063); b=md5ff(b,c,d,a,M(11),22,-1990404162);
|
|
30
|
+
a=md5ff(a,b,c,d,M(12),7,1804603682); d=md5ff(d,a,b,c,M(13),12,-40341101); c=md5ff(c,d,a,b,M(14),17,-1502002290); b=md5ff(b,c,d,a,M(15),22,1236535329);
|
|
31
|
+
a=md5gg(a,b,c,d,M(1),5,-165796510); d=md5gg(d,a,b,c,M(6),9,-1069501632); c=md5gg(c,d,a,b,M(11),14,643717713); b=md5gg(b,c,d,a,M(0),20,-373897302);
|
|
32
|
+
a=md5gg(a,b,c,d,M(5),5,-701558691); d=md5gg(d,a,b,c,M(10),9,38016083); c=md5gg(c,d,a,b,M(15),14,-660478335); b=md5gg(b,c,d,a,M(4),20,-405537848);
|
|
33
|
+
a=md5gg(a,b,c,d,M(9),5,568446438); d=md5gg(d,a,b,c,M(14),9,-1019803690); c=md5gg(c,d,a,b,M(3),14,-187363961); b=md5gg(b,c,d,a,M(8),20,1163531501);
|
|
34
|
+
a=md5gg(a,b,c,d,M(13),5,-1444681467); d=md5gg(d,a,b,c,M(2),9,-51403784); c=md5gg(c,d,a,b,M(7),14,1735328473); b=md5gg(b,c,d,a,M(12),20,-1926607734);
|
|
35
|
+
a=md5hh(a,b,c,d,M(5),4,-378558); d=md5hh(d,a,b,c,M(8),11,-2022574463); c=md5hh(c,d,a,b,M(11),16,1839030562); b=md5hh(b,c,d,a,M(14),23,-35309556);
|
|
36
|
+
a=md5hh(a,b,c,d,M(1),4,-1530992060); d=md5hh(d,a,b,c,M(4),11,1272893353); c=md5hh(c,d,a,b,M(7),16,-155497632); b=md5hh(b,c,d,a,M(10),23,-1094730640);
|
|
37
|
+
a=md5hh(a,b,c,d,M(13),4,681279174); d=md5hh(d,a,b,c,M(0),11,-358537222); c=md5hh(c,d,a,b,M(3),16,-722521979); b=md5hh(b,c,d,a,M(6),23,76029189);
|
|
38
|
+
a=md5hh(a,b,c,d,M(9),4,-640364487); d=md5hh(d,a,b,c,M(12),11,-421815835); c=md5hh(c,d,a,b,M(15),16,530742520); b=md5hh(b,c,d,a,M(2),23,-995338651);
|
|
39
|
+
a=md5ii(a,b,c,d,M(0),6,-198630844); d=md5ii(d,a,b,c,M(7),10,1126891415); c=md5ii(c,d,a,b,M(14),15,-1416354905); b=md5ii(b,c,d,a,M(5),21,-57434055);
|
|
40
|
+
a=md5ii(a,b,c,d,M(12),6,1700485571); d=md5ii(d,a,b,c,M(3),10,-1894986606); c=md5ii(c,d,a,b,M(10),15,-1051523); b=md5ii(b,c,d,a,M(1),21,-2054922799);
|
|
41
|
+
a=md5ii(a,b,c,d,M(8),6,1873313359); d=md5ii(d,a,b,c,M(15),10,-30611744); c=md5ii(c,d,a,b,M(6),15,-1560198380); b=md5ii(b,c,d,a,M(13),21,1309151649);
|
|
42
|
+
a=md5ii(a,b,c,d,M(4),6,-145523070); d=md5ii(d,a,b,c,M(11),10,-1120210379); c=md5ii(c,d,a,b,M(2),15,718787259); b=md5ii(b,c,d,a,M(9),21,-343485551);
|
|
43
|
+
a=safeAdd(a,oa); b=safeAdd(b,ob); c=safeAdd(c,oc); d=safeAdd(d,od);
|
|
44
|
+
}
|
|
45
|
+
const result = new DataView(new ArrayBuffer(16));
|
|
46
|
+
result.setUint32(0, a, true); result.setUint32(4, b, true); result.setUint32(8, c, true); result.setUint32(12, d, true);
|
|
47
|
+
return Array.from(new Uint8Array(result.buffer));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Returns the MD5 hash of the given bytes as a lowercase hex string. */
|
|
51
|
+
export function md5Hex(input: Uint8Array): string {
|
|
52
|
+
return md5Bytes(input).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Returns the MD5 hash of the given bytes as a raw byte array. */
|
|
56
|
+
export function md5AsBytes(input: Uint8Array): number[] {
|
|
57
|
+
return md5Bytes(input);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Returns the SHA-256 hash of the given buffer as a base64 string. */
|
|
61
|
+
export function sha256Base64(buffer: ArrayBuffer): Promise<string> {
|
|
62
|
+
return crypto.subtle.digest("SHA-256", new Uint8Array(buffer)).then(res =>
|
|
63
|
+
btoa(String.fromCharCode(...new Uint8Array(res)))
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { madeWithNeedleSVG, needleLogoOnlySVG, needleLogoSVG } from "../assets/index.js";
|
|
2
|
+
import { HTMLElementBase } from "../engine_ssr.js";
|
|
2
3
|
|
|
3
4
|
const elementName = "needle-logo-element";
|
|
4
5
|
|
|
@@ -12,7 +13,7 @@ declare global {
|
|
|
12
13
|
* Needle logo web component used in the hosting UI (small, compact logo or full)
|
|
13
14
|
* @element needle-logo-element
|
|
14
15
|
*/
|
|
15
|
-
export class NeedleLogoElement extends
|
|
16
|
+
export class NeedleLogoElement extends HTMLElementBase {
|
|
16
17
|
|
|
17
18
|
static get elementName() { return elementName; }
|
|
18
19
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { showBalloonMessage } from "../../debug/debug.js";
|
|
2
|
+
import { HTMLElementBase } from "../../engine_ssr.js";
|
|
2
3
|
import type { Context } from "../../engine_context.js";
|
|
3
4
|
import { hasCommercialLicense, onLicenseCheckResultChanged, Telemetry } from "../../engine_license.js";
|
|
4
5
|
import { isLocalNetwork } from "../../engine_networking_utils.js";
|
|
@@ -303,7 +304,7 @@ export class NeedleMenu {
|
|
|
303
304
|
*
|
|
304
305
|
* @element needle-menu
|
|
305
306
|
*/
|
|
306
|
-
export class NeedleMenuElement extends
|
|
307
|
+
export class NeedleMenuElement extends HTMLElementBase {
|
|
307
308
|
|
|
308
309
|
static create() {
|
|
309
310
|
// Ensure the element is registered before creating — guards against
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isDevEnvironment } from "../debug/index.js";
|
|
2
|
+
import { HTMLElementBase } from "../engine_ssr.js";
|
|
2
3
|
import { ButtonsFactory } from "./buttons.js";
|
|
3
4
|
import { iconFontUrl, loadFont } from "./fonts.js";
|
|
4
5
|
import { WebXRButtonFactory } from "./WebXRButtons.js";
|
|
@@ -65,7 +66,7 @@ const isDev = isDevEnvironment();
|
|
|
65
66
|
* @see {@link NeedleEngineWebComponent} for the main <needle-engine> element
|
|
66
67
|
* @see {@link NeedleMenu} for the built-in menu component that can display similar buttons
|
|
67
68
|
*/
|
|
68
|
-
export class NeedleButtonElement extends
|
|
69
|
+
export class NeedleButtonElement extends HTMLElementBase {
|
|
69
70
|
|
|
70
71
|
static observedAttributes = ["ar", "vr", "quicklook", "qrcode"];
|
|
71
72
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isDevEnvironment, showBalloonWarning } from "../debug/index.js";
|
|
2
|
+
import { HTMLElementBase } from "../engine_ssr.js";
|
|
2
3
|
import { PUBLIC_KEY, VERSION } from "../engine_constants.js";
|
|
3
4
|
import { ContextEvent, ContextRegistry } from "../engine_context_registry.js";
|
|
4
5
|
import { hasCommercialLicense } from "../engine_license.js";
|
|
@@ -153,7 +154,7 @@ const observedAttributes = [
|
|
|
153
154
|
* @see {@link NeedleButtonElement} for adding AR/VR/Quicklook buttons via <needle-button>
|
|
154
155
|
* @see {@link NeedleMenu} for the built-in menu configuration component
|
|
155
156
|
*/
|
|
156
|
-
export class NeedleEngineWebComponent extends
|
|
157
|
+
export class NeedleEngineWebComponent extends HTMLElementBase implements INeedleEngineComponent {
|
|
157
158
|
|
|
158
159
|
static get observedAttributes() {
|
|
159
160
|
return observedAttributes;
|
|
@@ -207,7 +207,7 @@ function waitForContextLoadingFinished(): Promise<void> {
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
|
|
210
|
-
if (DeviceUtilities.isDesktop() && isDevEnvironment()) {
|
|
210
|
+
if (typeof window !== "undefined" && DeviceUtilities.isDesktop() && isDevEnvironment()) {
|
|
211
211
|
window.addEventListener("keydown", (evt) => {
|
|
212
212
|
if (evt.key === "x" || evt.key === "Escape") {
|
|
213
213
|
if (NeedleXRSession.active) {
|
|
@@ -382,12 +382,12 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
382
382
|
this._watch.start(true, true);
|
|
383
383
|
this.startCoroutine(this.beforePhysics(), FrameEvent.LateUpdate);
|
|
384
384
|
if (isDevEnvironment()) {
|
|
385
|
-
if (
|
|
386
|
-
console.warn(`
|
|
385
|
+
if (globalThis["NEEDLE_USE_RAPIER"] === false)
|
|
386
|
+
console.warn(`RAPIER physics are disabled in your build. Enable them by setting NEEDLE_USE_RAPIER to true in your build config: Rigidbody could not be created.`);
|
|
387
387
|
else {
|
|
388
388
|
MODULES.RAPIER_PHYSICS.ready().then(async () => {
|
|
389
389
|
await delayForFrames(3);
|
|
390
|
-
if (!this.context.physics.engine?.getBody(this))
|
|
390
|
+
if (this.activeAndEnabled && !this.context.physics.engine?.getBody(this))
|
|
391
391
|
console.warn(`Rigidbody could not be created. Ensure \"${this.name}\" has a Collider component.`);
|
|
392
392
|
})
|
|
393
393
|
}
|
|
@@ -723,6 +723,7 @@ export class SceneSwitcher extends Behaviour {
|
|
|
723
723
|
// unless the user defines that he wants to use the scene name
|
|
724
724
|
if (this.useSceneName) {
|
|
725
725
|
if (scene instanceof Object3D) queryParameterValue = scene.name;
|
|
726
|
+
else if (scene instanceof AssetReference && scene.asset?.name) queryParameterValue = scene.asset.name;
|
|
726
727
|
else if (scene.url) queryParameterValue = sceneUriToName(scene.url);
|
|
727
728
|
}
|
|
728
729
|
// save the loaded scene as an url parameter
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { EffectAttribute } from "postprocessing";
|
|
2
1
|
import { Uniform } from "three";
|
|
3
2
|
|
|
4
3
|
import { MODULES } from "../../../engine/engine_modules.js";
|
|
@@ -138,7 +137,7 @@ function createSharpeningEffectType() {
|
|
|
138
137
|
["radius", new Uniform(1)],
|
|
139
138
|
// ["threshold", new Uniform(0)],
|
|
140
139
|
]),
|
|
141
|
-
attributes: EffectAttribute.CONVOLUTION
|
|
140
|
+
attributes: MODULES.POSTPROCESSING.MODULE.EffectAttribute.CONVOLUTION
|
|
142
141
|
});
|
|
143
142
|
}
|
|
144
143
|
}
|
|
@@ -14,10 +14,6 @@ import { threeToneMappingToEffectMode } from "./Effects/Tonemapping.utils.js";
|
|
|
14
14
|
import { PostProcessingEffect, PostProcessingEffectContext } from "./PostProcessingEffect.js";
|
|
15
15
|
import { orderEffects, PostprocessingEffectData, PostProcessingEffectOrder } from "./utils.js";
|
|
16
16
|
|
|
17
|
-
declare const NEEDLE_USE_POSTPROCESSING: boolean;
|
|
18
|
-
globalThis["NEEDLE_USE_POSTPROCESSING"] = globalThis["NEEDLE_USE_POSTPROCESSING"] !== undefined ? globalThis["NEEDLE_USE_POSTPROCESSING"] : true;
|
|
19
|
-
|
|
20
|
-
|
|
21
17
|
const debug = getParam("debugpost");
|
|
22
18
|
|
|
23
19
|
const activeKey = Symbol("needle:postprocessing-handler");
|
|
@@ -58,13 +54,13 @@ export class PostProcessingHandler implements IPostProcessingHandler {
|
|
|
58
54
|
|
|
59
55
|
apply(components: PostProcessingEffect[]): Promise<void> {
|
|
60
56
|
if ("env" in import.meta && (import.meta as any /* webpack support */ ).env.VITE_NEEDLE_USE_POSTPROCESSING === "false") {
|
|
61
|
-
if (debug) console.warn("
|
|
62
|
-
else console.debug("
|
|
57
|
+
if (debug) console.warn("POSTPROCESSING is disabled via vite env setting");
|
|
58
|
+
else console.debug("POSTPROCESSING is disabled via vite env setting");
|
|
63
59
|
return Promise.resolve();
|
|
64
60
|
}
|
|
65
61
|
if (!NEEDLE_USE_POSTPROCESSING) {
|
|
66
|
-
if (debug) console.warn("
|
|
67
|
-
else console.debug("
|
|
62
|
+
if (debug || isDevEnvironment()) console.warn("POSTPROCESSING is disabled via global vite define setting");
|
|
63
|
+
else console.debug("POSTPROCESSING is disabled via vite define");
|
|
68
64
|
return Promise.resolve();
|
|
69
65
|
}
|
|
70
66
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// For firefox ViewTimeline support
|
|
2
|
-
|
|
1
|
+
// For firefox ViewTimeline support — dynamic import to avoid SSR crashes (polyfill accesses window at module level)
|
|
2
|
+
if (typeof window !== "undefined") import("scroll-timeline-polyfill/dist/scroll-timeline.js");
|
|
3
3
|
|
|
4
4
|
import { Box3, Object3D } from "three";
|
|
5
5
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Vite global defines — see plugins/vite/defines.js
|
|
2
|
+
// declare const entries here are picked up globally (ambient, no import/export).
|
|
3
|
+
// Vite sets these as globals in dev and statically replaces them at build time.
|
|
4
|
+
// Webpack DefinePlugin replaces them at build time too.
|
|
5
|
+
// The globalThis fallbacks for vanilla JS are in engine_constants.ts.
|
|
6
|
+
|
|
7
|
+
declare const NEEDLE_ENGINE_VERSION: string;
|
|
8
|
+
declare const NEEDLE_ENGINE_GENERATOR: string;
|
|
9
|
+
declare const NEEDLE_PROJECT_BUILD_TIME: string;
|
|
10
|
+
declare const NEEDLE_PUBLIC_KEY: string;
|
|
11
|
+
|
|
12
|
+
// #region treeshake flags
|
|
13
|
+
// declare var (not const) so globalThis["NEEDLE_USE_*"] access is also type-safe
|
|
14
|
+
declare var NEEDLE_USE_RAPIER: boolean;
|
|
15
|
+
declare var NEEDLE_USE_POSTPROCESSING: boolean;
|
|
16
|
+
// #endregion treeshake flags
|