@needle-tools/engine 4.8.3-next.1a41273 → 4.8.3-next.64a46ce
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/dist/{gltf-progressive-B--ZfCTJ.min.js → gltf-progressive-DLhfUtEV.min.js} +1 -1
- package/dist/{gltf-progressive-Do1XJNMG.js → gltf-progressive-DVx_cW0s.js} +1 -5
- package/dist/{needle-engine.bundle-CcYGQALb.umd.cjs → needle-engine.bundle-BQqY5DIa.umd.cjs} +11 -11
- package/dist/{needle-engine.bundle-DbnDoLkt.js → needle-engine.bundle-CPCPUPEo.js} +148 -151
- package/dist/{needle-engine.bundle-CvDGadt9.min.js → needle-engine.bundle-s1gEDSWN.min.js} +24 -24
- package/dist/needle-engine.js +3 -3
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/engine_context.d.ts +1 -1
- package/lib/engine/engine_context.js +5 -12
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_networking_streams.js +7 -2
- package/lib/engine/engine_networking_streams.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +1 -0
- package/lib/engine-components/OrbitControls.js +6 -0
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/package.json +1 -1
- package/plugins/vite/peer.js +60 -2
- package/plugins/vite/poster-client.js +35 -51
- package/plugins/vite/poster.js +2 -3
- package/src/engine/engine_context.ts +7 -12
- package/src/engine/engine_networking_streams.ts +8 -4
- package/src/engine-components/OrbitControls.ts +5 -0
package/plugins/vite/peer.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
1
|
const peerjsString = `/* needle: fix for peerjs */ window.global = window; var parcelRequire;`
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* @param {import('../types').userSettings} userSettings
|
|
5
|
+
* @returns {import("vite").Plugin | undefined}
|
|
6
6
|
*/
|
|
7
7
|
export const needlePeerjs = (command, config, userSettings) => {
|
|
8
8
|
|
|
@@ -23,7 +23,65 @@ export const needlePeerjs = (command, config, userSettings) => {
|
|
|
23
23
|
},
|
|
24
24
|
]
|
|
25
25
|
}
|
|
26
|
-
}
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
enforce: "pre",
|
|
29
|
+
transform: (code, id) => {
|
|
30
|
+
return patchWebRTCAdapterForGemini(code, id);
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
33
|
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} code
|
|
40
|
+
* @param {string} id
|
|
41
|
+
* @returns {string | undefined}
|
|
42
|
+
*/
|
|
43
|
+
function patchWebRTCAdapterForGemini(code, id) {
|
|
44
|
+
// Match navigator.mediaDevices.getUserMedia assignments
|
|
45
|
+
const assignmentRegex = /(navigator\d{0,1})\.mediaDevices\.getUserMedia\s*=\s*function/gm;
|
|
46
|
+
|
|
47
|
+
let didTransform = false;
|
|
48
|
+
let transformedCode = code;
|
|
49
|
+
let match;
|
|
50
|
+
|
|
51
|
+
while ((match = assignmentRegex.exec(code)) !== null) {
|
|
52
|
+
const navigatorRef = match[1];
|
|
53
|
+
const matchStart = match.index;
|
|
54
|
+
|
|
55
|
+
// Find the end of the function assignment
|
|
56
|
+
let braceCount = 0;
|
|
57
|
+
let inFunction = false;
|
|
58
|
+
let endIndex = matchStart;
|
|
59
|
+
|
|
60
|
+
for (let i = matchStart; i < code.length; i++) {
|
|
61
|
+
const char = code[i];
|
|
62
|
+
if (char === '{') {
|
|
63
|
+
braceCount++;
|
|
64
|
+
inFunction = true;
|
|
65
|
+
} else if (char === '}') {
|
|
66
|
+
braceCount--;
|
|
67
|
+
if (inFunction && braceCount === 0) {
|
|
68
|
+
endIndex = i + 1;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const originalAssignment = code.substring(matchStart, endIndex);
|
|
75
|
+
const wrappedAssignment = `if (Object.getOwnPropertyDescriptor(${navigatorRef}.mediaDevices, "getUserMedia")?.writable) {\n ${originalAssignment}\n}`;
|
|
76
|
+
didTransform = true;
|
|
77
|
+
transformedCode = transformedCode.replace(originalAssignment, wrappedAssignment);
|
|
78
|
+
// console.log("-------------------------------\nTRANSFORMED\n", id, "\nOriginal:", originalAssignment, "\nWrapped:", wrappedAssignment, "\n\n");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if(!didTransform) return undefined;
|
|
82
|
+
|
|
83
|
+
console.log("[needle:peerjs] Fixed WebRTC assignment");
|
|
84
|
+
|
|
85
|
+
return transformedCode;
|
|
86
|
+
|
|
87
|
+
}
|
|
@@ -1,40 +1,46 @@
|
|
|
1
1
|
|
|
2
2
|
async function generatePoster() {
|
|
3
|
-
const { screenshot2 } = await import("@needle-tools/engine");
|
|
4
3
|
|
|
5
4
|
try {
|
|
6
|
-
const
|
|
7
|
-
if (!needleEngine) return null;
|
|
5
|
+
const { screenshot2, onStart } = await import("@needle-tools/engine");
|
|
8
6
|
|
|
9
7
|
// Keep in sync with og:image:width meta tags
|
|
10
8
|
// https://developers.facebook.com/docs/sharing/best-practices/
|
|
11
9
|
const width = 1080;
|
|
12
10
|
const height = 1080;
|
|
13
|
-
const context = await needleEngine.getContext();
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
12
|
+
return new Promise(res => {
|
|
13
|
+
onStart(async context => {
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
if (context.lodsManager.manager) {
|
|
16
|
+
await context.lodsManager.manager.awaitLoading({ frames: 20, maxPromisesPerObject: 2 });
|
|
17
|
+
}
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
const mimeType = "image/webp";
|
|
20
|
+
|
|
21
|
+
// We're reading back as a blob here because that's async, and doesn't seem
|
|
22
|
+
// to stress the GPU so much on memory-constrained devices.
|
|
23
|
+
const blob = await screenshot2({ context, width, height, mimeType, type: "blob" });
|
|
24
|
+
|
|
25
|
+
// We can only send a DataURL, so we need to convert it back here.
|
|
26
|
+
const dataUrl = await new Promise((resolve, reject) => {
|
|
27
|
+
const reader = new FileReader();
|
|
28
|
+
reader.onload = function () {
|
|
29
|
+
resolve(reader.result);
|
|
30
|
+
};
|
|
31
|
+
reader.onloadend = function () {
|
|
32
|
+
resolve(null);
|
|
33
|
+
};
|
|
34
|
+
reader.readAsDataURL(blob);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
res(dataUrl);
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
}, { once: true });
|
|
42
|
+
})
|
|
36
43
|
|
|
37
|
-
return dataUrl;
|
|
38
44
|
}
|
|
39
45
|
catch (e) {
|
|
40
46
|
console.error(e);
|
|
@@ -42,33 +48,11 @@ async function generatePoster() {
|
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
async function sendPoster() {
|
|
46
|
-
const blob = await generatePoster();
|
|
47
|
-
import.meta.hot.send("needle:screenshot", { data: blob });
|
|
48
|
-
}
|
|
49
51
|
|
|
50
|
-
// communicate via vite
|
|
51
52
|
if (import.meta.hot) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
sendPoster();
|
|
58
|
-
}, 200);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// for debugging: build extra button with dev-only options
|
|
62
|
-
/*
|
|
63
|
-
var button = document.createElement("button");
|
|
64
|
-
button.id = "send-msg";
|
|
65
|
-
button.innerHTML = "Generate Poster";
|
|
66
|
-
button.style.position = "fixed";
|
|
67
|
-
button.style.zIndex = "9999";
|
|
68
|
-
document.body.appendChild(button);
|
|
69
|
-
|
|
70
|
-
document.querySelector("#send-msg").addEventListener("click", async () => {
|
|
71
|
-
sendPoster();
|
|
72
|
-
});
|
|
73
|
-
*/
|
|
53
|
+
async function run() {
|
|
54
|
+
const blob = await generatePoster();
|
|
55
|
+
import.meta.hot.send("needle:screenshot", { data: blob });
|
|
56
|
+
}
|
|
57
|
+
run();
|
|
74
58
|
}
|
package/plugins/vite/poster.js
CHANGED
|
@@ -36,7 +36,7 @@ export const needlePoster = (command, config, userSettings) => {
|
|
|
36
36
|
}
|
|
37
37
|
try {
|
|
38
38
|
const targetPath = "./" + getPosterPath();
|
|
39
|
-
console.debug(`
|
|
39
|
+
console.debug(`[needle:poster] Saving automatic poster to ${targetPath}`);
|
|
40
40
|
// remove data:image/png;base64, from the beginning of the string
|
|
41
41
|
if (targetPath.endsWith(".webp"))
|
|
42
42
|
data.data = data.data.replace(/^data:image\/webp;base64,/, "");
|
|
@@ -47,10 +47,9 @@ export const needlePoster = (command, config, userSettings) => {
|
|
|
47
47
|
fs.mkdirSync(dir, { recursive: true })
|
|
48
48
|
}
|
|
49
49
|
fs.writeFileSync(targetPath, Buffer.from(data.data, "base64"));
|
|
50
|
-
console.debug("Saved poster to file");
|
|
51
50
|
}
|
|
52
51
|
catch (err) {
|
|
53
|
-
console.error("Failed to save poster", err.message);
|
|
52
|
+
console.error("[needle:poster] Failed to save poster", err.message);
|
|
54
53
|
}
|
|
55
54
|
});
|
|
56
55
|
},
|
|
@@ -980,14 +980,14 @@ export class Context implements IContext {
|
|
|
980
980
|
if (this.isInXR) return true;
|
|
981
981
|
if (!this._isVisible) return false;
|
|
982
982
|
// Make sure not to call getComputedStyle multiple times per frame
|
|
983
|
-
if (this.
|
|
984
|
-
this.
|
|
983
|
+
if (!this._needsVisibleUpdate && this._lastStyleComputedResult !== undefined) return this._lastStyleComputedResult;
|
|
984
|
+
this._needsVisibleUpdate = false;
|
|
985
985
|
const style = getComputedStyle(this.domElement);
|
|
986
986
|
this._lastStyleComputedResult = style.visibility !== "hidden" && style.display !== "none" && style.opacity !== "0";
|
|
987
987
|
return this._lastStyleComputedResult;
|
|
988
988
|
}
|
|
989
|
-
private
|
|
990
|
-
private _lastStyleComputedResult: boolean =
|
|
989
|
+
private _needsVisibleUpdate: boolean = true;
|
|
990
|
+
private _lastStyleComputedResult: boolean | undefined = undefined;
|
|
991
991
|
|
|
992
992
|
private _createId: number = 0;
|
|
993
993
|
private async internalOnCreate(opts?: ContextCreateArgs): Promise<boolean> {
|
|
@@ -1391,6 +1391,7 @@ export class Context implements IContext {
|
|
|
1391
1391
|
this.renderer.info.reset();
|
|
1392
1392
|
}
|
|
1393
1393
|
|
|
1394
|
+
this._needsVisibleUpdate = true;
|
|
1394
1395
|
|
|
1395
1396
|
const sessionStarted = frame !== null && this._xrFrame === null;
|
|
1396
1397
|
this._xrFrame = frame;
|
|
@@ -1420,8 +1421,8 @@ export class Context implements IContext {
|
|
|
1420
1421
|
|
|
1421
1422
|
Context.Current = this;
|
|
1422
1423
|
this.time.update();
|
|
1423
|
-
|
|
1424
|
-
|
|
1424
|
+
|
|
1425
|
+
if (debugframerate) console.log("FPS", (this.time.smoothedFps).toFixed(0));
|
|
1425
1426
|
|
|
1426
1427
|
|
|
1427
1428
|
looputils.processNewScripts(this);
|
|
@@ -1460,7 +1461,6 @@ export class Context implements IContext {
|
|
|
1460
1461
|
}
|
|
1461
1462
|
this.executeCoroutines(FrameEvent.EarlyUpdate);
|
|
1462
1463
|
invokeLifecycleFunctions(this, FrameEvent.EarlyUpdate);
|
|
1463
|
-
if (this.onHandlePaused()) return false;
|
|
1464
1464
|
|
|
1465
1465
|
this._currentFrameEvent = FrameEvent.Update;
|
|
1466
1466
|
|
|
@@ -1474,8 +1474,6 @@ export class Context implements IContext {
|
|
|
1474
1474
|
}
|
|
1475
1475
|
this.executeCoroutines(FrameEvent.Update);
|
|
1476
1476
|
invokeLifecycleFunctions(this, FrameEvent.Update);
|
|
1477
|
-
if (this.onHandlePaused()) return false;
|
|
1478
|
-
|
|
1479
1477
|
this._currentFrameEvent = FrameEvent.LateUpdate;
|
|
1480
1478
|
|
|
1481
1479
|
for (let i = 0; i < this.scripts_lateUpdate.length; i++) {
|
|
@@ -1490,7 +1488,6 @@ export class Context implements IContext {
|
|
|
1490
1488
|
// this.mainLight = null;
|
|
1491
1489
|
this.executeCoroutines(FrameEvent.LateUpdate);
|
|
1492
1490
|
invokeLifecycleFunctions(this, FrameEvent.LateUpdate);
|
|
1493
|
-
if (this.onHandlePaused()) return false;
|
|
1494
1491
|
|
|
1495
1492
|
if (this.physicsSteps === undefined) {
|
|
1496
1493
|
this.physicsSteps = 1;
|
|
@@ -1499,8 +1496,6 @@ export class Context implements IContext {
|
|
|
1499
1496
|
this.internalUpdatePhysics(this.physicsSteps);
|
|
1500
1497
|
}
|
|
1501
1498
|
|
|
1502
|
-
if (this.onHandlePaused()) return false;
|
|
1503
|
-
|
|
1504
1499
|
if (this.isVisibleToUser || this.runInBackground) {
|
|
1505
1500
|
|
|
1506
1501
|
this._currentFrameEvent = FrameEvent.OnBeforeRender;
|
|
@@ -237,11 +237,15 @@ export class PeerHandle extends EventDispatcher<any> {
|
|
|
237
237
|
this.context = context;
|
|
238
238
|
this.id = id;
|
|
239
239
|
this.setupPeer();
|
|
240
|
+
const isGetUserMediaWriteable = Object.getOwnPropertyDescriptor(navigator, "getUserMedia")?.writable;
|
|
240
241
|
try {
|
|
241
|
-
|
|
242
|
-
navigator["getUserMedia"]
|
|
243
|
-
|
|
244
|
-
|
|
242
|
+
if (isGetUserMediaWriteable) {
|
|
243
|
+
navigator["getUserMedia"] = (
|
|
244
|
+
navigator["getUserMedia"] || navigator["webkitGetUserMedia"] ||
|
|
245
|
+
navigator["mozGetUserMedia"] || navigator["msGetUserMedia"]
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
else if (debug) console.warn("[PeerJs] getUserMedia is not writable");
|
|
245
249
|
}
|
|
246
250
|
catch (err) {
|
|
247
251
|
if (debug) console.error("[PeerJs] Error setting getUserMedia", err);
|
|
@@ -565,6 +565,11 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
565
565
|
}
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
+
onPausedChanged(isPaused: boolean): void {
|
|
569
|
+
if (!this._controls) return;
|
|
570
|
+
if (isPaused) this._controls.enabled = false;
|
|
571
|
+
}
|
|
572
|
+
|
|
568
573
|
|
|
569
574
|
/** @internal */
|
|
570
575
|
onBeforeRender() {
|