@needle-tools/engine 5.1.4 → 5.1.5
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 +6 -0
- package/dist/{needle-engine.bundle-CEba8eTv.js → needle-engine.bundle-CxsZfV6C.js} +5245 -5166
- package/dist/{needle-engine.bundle-BvxvjlSN.min.js → needle-engine.bundle-DUb8msPR.min.js} +140 -140
- package/dist/{needle-engine.bundle-GUaSFX8u.umd.cjs → needle-engine.bundle-D_h1sDs-.umd.cjs} +137 -137
- package/dist/needle-engine.d.ts +39 -30
- package/dist/needle-engine.js +242 -242
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/api.d.ts +1 -1
- package/lib/engine/api.js +1 -1
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug_console.js +39 -17
- package/lib/engine/debug/debug_console.js.map +1 -1
- package/lib/engine/debug/debug_spatial_console.js +14 -0
- package/lib/engine/debug/debug_spatial_console.js.map +1 -1
- package/lib/engine/engine_init.js +2 -2
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_license.d.ts +7 -7
- package/lib/engine/engine_license.js +71 -71
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_networking_blob.js +3 -3
- package/lib/engine/engine_utils_qrcode.js +2 -2
- package/lib/engine/engine_utils_screenshot.js +1 -0
- package/lib/engine/engine_utils_screenshot.js.map +1 -1
- package/lib/engine/engine_utils_screenshot.xr.js +1 -1
- package/lib/engine/engine_utils_screenshot.xr.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu.js +18 -5
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.ar-overlay.js +33 -7
- package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.js +2 -2
- package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.js +10 -4
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine/xr/NeedleXRSync.js +47 -47
- package/lib/engine/xr/NeedleXRSync.js.map +1 -1
- package/lib/engine/xr/TempXRContext.js +2 -2
- package/lib/engine-components/DragControls.d.ts +9 -0
- package/lib/engine-components/DragControls.js +174 -73
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/DragControlsConstraints.d.ts +11 -2
- package/lib/engine-components/DragControlsConstraints.js +18 -11
- package/lib/engine-components/DragControlsConstraints.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +32 -6
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.js +4 -4
- package/package.json +1 -1
- package/plugins/common/license.js +4 -4
- package/plugins/vite/license.js +4 -4
- package/src/engine/api.ts +1 -1
- package/src/engine/debug/debug_console.ts +33 -17
- package/src/engine/debug/debug_spatial_console.ts +15 -0
- package/src/engine/engine_init.ts +2 -2
- package/src/engine/engine_license.ts +68 -68
- package/src/engine/engine_networking_blob.ts +3 -3
- package/src/engine/engine_utils_qrcode.ts +2 -2
- package/src/engine/engine_utils_screenshot.ts +1 -0
- package/src/engine/engine_utils_screenshot.xr.ts +1 -1
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
- package/src/engine/webcomponents/needle menu/needle-menu.ts +19 -5
- package/src/engine/webcomponents/needle-engine.ar-overlay.ts +33 -5
- package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
- package/src/engine/webcomponents/needle-engine.ts +2 -2
- package/src/engine/xr/NeedleXRSession.ts +10 -3
- package/src/engine/xr/NeedleXRSync.ts +47 -50
- package/src/engine/xr/TempXRContext.ts +2 -2
- package/src/engine-components/DragControls.ts +189 -80
- package/src/engine-components/DragControlsConstraints.ts +20 -12
- package/src/engine-components/OrbitControls.ts +31 -4
- package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
|
@@ -398,8 +398,11 @@ export class PlaneHeightLockConstraint implements IDragConstraint {
|
|
|
398
398
|
|
|
399
399
|
/**
|
|
400
400
|
* Used by {@link SnapToSurfacesDragStrategy} for two-pointer (multi-touch) drags.
|
|
401
|
-
*
|
|
402
|
-
*
|
|
401
|
+
* Each frame `MultiTouchDragHandler` aims the snap ray from the pointer origin(s) through the
|
|
402
|
+
* current two-finger grab midpoint (see {@link setRay}); apply() casts that ray into the scene
|
|
403
|
+
* and places the follow object so its bounding-box contact face rests on the hit surface with
|
|
404
|
+
* the object origin at the hit point — the same "snap to what the pointer points at" semantics
|
|
405
|
+
* as the single-pointer surface raycast.
|
|
403
406
|
*
|
|
404
407
|
* Only injected into the constraint pipeline for multi-touch; the single-pointer path
|
|
405
408
|
* continues to use {@link SnapToSurfacesDragStrategy.update} (pointer ray + drag plane
|
|
@@ -409,6 +412,10 @@ export class SnapToSurfaceConstraint implements IDragConstraint {
|
|
|
409
412
|
private _gameObject: Object3D | null = null;
|
|
410
413
|
private _boundsAtScaleOne: Box3 | null = null;
|
|
411
414
|
|
|
415
|
+
/** Snap ray for the current frame. Valid only after {@link setRay}; apply() is a no-op until then. */
|
|
416
|
+
private readonly _ray = new Ray();
|
|
417
|
+
private _hasRay = false;
|
|
418
|
+
|
|
412
419
|
// Per-frame scratch vectors — avoids per-frame allocations.
|
|
413
420
|
private readonly _t1 = new Vector3();
|
|
414
421
|
private readonly _t2 = new Vector3();
|
|
@@ -420,19 +427,23 @@ export class SnapToSurfaceConstraint implements IDragConstraint {
|
|
|
420
427
|
init(ctx: IDragConstraintContext): void {
|
|
421
428
|
this._gameObject = ctx.gameObject;
|
|
422
429
|
this._boundsAtScaleOne = ctx.boundsAtScaleOne;
|
|
430
|
+
this._hasRay = false;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** Sets the world-space snap ray for this frame. Called by `MultiTouchDragHandler` before the
|
|
434
|
+
* constraint pipeline runs. `direction` must be normalized. */
|
|
435
|
+
setRay(origin: Vector3, direction: Vector3): void {
|
|
436
|
+
this._ray.origin.copy(origin);
|
|
437
|
+
this._ray.direction.copy(direction);
|
|
438
|
+
this._hasRay = true;
|
|
423
439
|
}
|
|
424
440
|
|
|
425
441
|
apply(followObject: GameObject): void {
|
|
426
|
-
if (!this._gameObject || !this._boundsAtScaleOne) return;
|
|
442
|
+
if (!this._gameObject || !this._boundsAtScaleOne || !this._hasRay) return;
|
|
427
443
|
|
|
428
|
-
// Cast a downward ray from 0.5 units above the follow object's current world position.
|
|
429
|
-
// The small upward offset avoids self-intersection when the object sits on a surface.
|
|
430
|
-
// World-Y down is used; it finds the nearest surface below the follow object.
|
|
431
444
|
const currentWP = followObject.worldPosition;
|
|
432
|
-
this._t1.set(currentWP.x, currentWP.y + 0.5, currentWP.z);
|
|
433
|
-
const ray = new Ray(this._t1, _snapToSurfaceDown);
|
|
434
445
|
|
|
435
|
-
const hits = this._context.physics.raycastFromRay(
|
|
446
|
+
const hits = this._context.physics.raycastFromRay(this._ray, {
|
|
436
447
|
testObject: (o: Object3D) => o !== (followObject as unknown as Object3D) && o !== this._gameObject
|
|
437
448
|
});
|
|
438
449
|
|
|
@@ -469,9 +480,6 @@ export class SnapToSurfaceConstraint implements IDragConstraint {
|
|
|
469
480
|
}
|
|
470
481
|
}
|
|
471
482
|
|
|
472
|
-
/** Shared downward direction vector for {@link SnapToSurfaceConstraint}. */
|
|
473
|
-
const _snapToSurfaceDown = new Vector3(0, -1, 0);
|
|
474
|
-
|
|
475
483
|
|
|
476
484
|
// #region Utilities
|
|
477
485
|
/**
|
|
@@ -778,12 +778,39 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
778
778
|
this._lookTargetEndPosition.clamp(min, max);
|
|
779
779
|
}
|
|
780
780
|
else {
|
|
781
|
-
// Interactive use (pan/orbit): smoothly push the target back into
|
|
781
|
+
// Interactive use (pan/orbit/zoom): smoothly push the target back into
|
|
782
|
+
// bounds as a RIGID shift — camera and target move by the same delta, so
|
|
783
|
+
// the camera-target offset is preserved (distance and viewing angles are
|
|
784
|
+
// untouched; the whole view slides back).
|
|
785
|
+
//
|
|
786
|
+
// Preserving the offset is load-bearing, not cosmetic: our three fork keeps
|
|
787
|
+
// a zoom-to-cursor gesture armed across frames until an update() settles
|
|
788
|
+
// with zero movement (required for damped zoom to converge). While armed,
|
|
789
|
+
// every update() re-derives `target` from the camera and turns any offset
|
|
790
|
+
// change into a dolly along the frozen cursor ray. Clamping only the target
|
|
791
|
+
// therefore changed the offset each frame, which re-derived the target
|
|
792
|
+
// outside the bounds again, which clamped again — a positive feedback loop
|
|
793
|
+
// that flung the camera away exponentially (observed 18m → 10^20m within
|
|
794
|
+
// ~70 frames). With a rigid shift the re-derived target reproduces the
|
|
795
|
+
// clamped one exactly, the correction decays geometrically and the gesture
|
|
796
|
+
// settles normally.
|
|
782
797
|
const targetVector = this._controls.target;
|
|
783
|
-
const
|
|
798
|
+
const delta = getTempVector(targetVector).clamp(min, max).sub(targetVector);
|
|
784
799
|
const duration = .1;
|
|
785
|
-
if (duration
|
|
786
|
-
|
|
800
|
+
if (duration > 0) delta.multiplyScalar(Math.min(1, this.context.time.deltaTime / duration));
|
|
801
|
+
targetVector.add(delta);
|
|
802
|
+
// Apply the IDENTICAL delta to the camera position, in the controls'
|
|
803
|
+
// own space: OrbitControls derives its state from
|
|
804
|
+
// `object.position - target` directly (parent-naive — three's own
|
|
805
|
+
// contract says the camera must not sit under a transformed parent,
|
|
806
|
+
// and all of the controls' math treats position and target as the
|
|
807
|
+
// same space). Converting the delta through the camera's parent
|
|
808
|
+
// scales it whenever an ancestor is scaled, so camera and target
|
|
809
|
+
// would move by different amounts — that changes the derived offset
|
|
810
|
+
// every frame and re-creates the feedback loop (verified: a 0.456×
|
|
811
|
+
// scaled ancestor turned the clamp into a ×2.19 camera shift and the
|
|
812
|
+
// runaway persisted).
|
|
813
|
+
this._cameraObject?.position.add(delta);
|
|
787
814
|
}
|
|
788
815
|
|
|
789
816
|
if (debug) {
|
|
@@ -3,7 +3,7 @@ import { Euler, Material, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from "t
|
|
|
3
3
|
|
|
4
4
|
import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../../../engine/debug/index.js";
|
|
5
5
|
import { findObjectOfType } from "../../../engine/engine_components.js";
|
|
6
|
-
import {
|
|
6
|
+
import { otIKt } from "../../../engine/engine_license.js";
|
|
7
7
|
import { serializable } from "../../../engine/engine_serialization.js";
|
|
8
8
|
import { getFormattedDate, Progress } from "../../../engine/engine_time_utils.js";
|
|
9
9
|
import { DeviceUtilities, getParam } from "../../../engine/engine_utils.js";
|
|
@@ -277,7 +277,7 @@ export class USDZExporter extends Behaviour {
|
|
|
277
277
|
let name = this.exportFileName ?? this.objectToExport?.name ?? this.name;
|
|
278
278
|
name += "-" + getFormattedDate(); // seems iOS caches the file in some cases, this ensures we always have a fresh file
|
|
279
279
|
|
|
280
|
-
if (!
|
|
280
|
+
if (!otIKt()) {
|
|
281
281
|
if (name !== "") name += "-";
|
|
282
282
|
name += "MadeWithNeedle";
|
|
283
283
|
}
|
|
@@ -682,7 +682,7 @@ export class USDZExporter extends Behaviour {
|
|
|
682
682
|
if (debug)
|
|
683
683
|
showBalloonMessage("Quicklook url: " + callToActionURL);
|
|
684
684
|
if (callToActionURL) {
|
|
685
|
-
if (!
|
|
685
|
+
if (!otIKt()) {
|
|
686
686
|
console.warn("Quicklook closed: custom redirects require a Needle Engine Pro license: https://needle.tools/pricing", callToActionURL)
|
|
687
687
|
}
|
|
688
688
|
else {
|
|
@@ -697,7 +697,7 @@ export class USDZExporter extends Behaviour {
|
|
|
697
697
|
private buildQuicklookOverlay(): CustomBranding {
|
|
698
698
|
const obj: CustomBranding = {};
|
|
699
699
|
if (this.customBranding) Object.assign(obj, this.customBranding);
|
|
700
|
-
if (!
|
|
700
|
+
if (!otIKt()) {
|
|
701
701
|
console.log("Custom Quicklook banner text requires pro license: https://needle.tools/pricing");
|
|
702
702
|
obj.callToAction = "Close";
|
|
703
703
|
obj.checkoutTitle = "🌵 Made with Needle";
|