@relu-interactives/spatial-ecs 0.8.0 → 0.10.0
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/{System-8D-XBDKZ.d.cts → System-BldSHxZV.d.cts} +214 -81
- package/dist/{System-DPMAW30g.d.ts → System-CADhPyQs.d.ts} +214 -81
- package/dist/{XRHandPose-G0Dl-F0w.d.ts → XRHandPose-BNSwd1y9.d.ts} +145 -2
- package/dist/{XRHandPose-VQMT1WXj.d.cts → XRHandPose-D3Ab1Dfs.d.cts} +145 -2
- package/dist/{chunk-G4XJ53LS.js → chunk-JEPUCLZX.js} +3 -3
- package/dist/{chunk-G4XJ53LS.js.map → chunk-JEPUCLZX.js.map} +1 -1
- package/dist/{chunk-NNDUOQ7O.js → chunk-JNYPJB55.js} +250 -3
- package/dist/chunk-JNYPJB55.js.map +1 -0
- package/dist/{chunk-SGF73YTF.js → chunk-NXASMBDS.js} +4 -4
- package/dist/{chunk-SGF73YTF.js.map → chunk-NXASMBDS.js.map} +1 -1
- package/dist/{chunk-JIJQFW6P.js → chunk-TY3XCHOR.js} +1390 -485
- package/dist/chunk-TY3XCHOR.js.map +1 -0
- package/dist/{chunk-U727NTWQ.js → chunk-WWP46AEF.js} +26 -4
- package/dist/chunk-WWP46AEF.js.map +1 -0
- package/dist/components/index.cjs +151 -0
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +3 -3
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.js +1 -1
- package/dist/docs/guide/bone-attachments-and-ik.md +1 -1
- package/dist/docs/guide/multiplayer.md +65 -0
- package/dist/docs/guide/spatial-ui.md +83 -7
- package/dist/factories/index.cjs +151 -0
- package/dist/factories/index.cjs.map +1 -1
- package/dist/factories/index.d.cts +2 -2
- package/dist/factories/index.d.ts +2 -2
- package/dist/factories/index.js +3 -3
- package/dist/{index-C61n65PE.d.ts → index-6pZO_gV7.d.ts} +27 -2
- package/dist/{index-D9DjrUn3.d.cts → index-BXjwEdNq.d.cts} +6 -3
- package/dist/{index-C70N4BYG.d.cts → index-BdghvXKE.d.cts} +27 -2
- package/dist/{index-DppafVu4.d.ts → index-CVG-hREM.d.ts} +6 -3
- package/dist/index.cjs +1800 -626
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -30
- package/dist/index.d.ts +8 -30
- package/dist/index.js +10 -10
- package/dist/network/index.cjs +858 -8
- package/dist/network/index.cjs.map +1 -1
- package/dist/network/index.d.cts +126 -5
- package/dist/network/index.d.ts +126 -5
- package/dist/network/index.js +683 -8
- package/dist/network/index.js.map +1 -1
- package/dist/systems/index.cjs +1702 -528
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +2 -2
- package/dist/systems/index.d.ts +2 -2
- package/dist/systems/index.js +4 -4
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/webgpu/index.d.ts +2 -2
- package/dist/worldSnapshotUtils.d.cts +1 -1
- package/dist/worldSnapshotUtils.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-JIJQFW6P.js.map +0 -1
- package/dist/chunk-NNDUOQ7O.js.map +0 -1
- package/dist/chunk-U727NTWQ.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getRendererKindOf, readWorldRenderBackend, readWorldRendererKind } from './chunk-OHCNPPMX.js';
|
|
2
|
-
import { resolveScriptCtor, Behaviour, normalizeScriptData, defaultModuleLoader, reportScriptError, serializeDataForStorage, toErrorMessage, readScriptPhase, withScriptPhase, mergeDataByCurrentDefaults, resolveInputData, resolvePrefabAssetUrl, reportBehaviourHookError } from './chunk-
|
|
3
|
-
import { createGLTFLoader, SHARED_MODEL_RESOURCE_FLAG, applyTransform, findModelBone } from './chunk-
|
|
4
|
-
import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, normalizeEnvironmentLighting, Environment, Postprocessing, TransformComponent, PhysicsComponent, setPhysicsLiveRef, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ScriptComponent, ScriptObjectComponent, AudioComponent, VideoComponent,
|
|
2
|
+
import { resolveScriptCtor, Behaviour, normalizeScriptData, defaultModuleLoader, reportScriptError, serializeDataForStorage, toErrorMessage, readScriptPhase, withScriptPhase, mergeDataByCurrentDefaults, resolveInputData, resolvePrefabAssetUrl, reportBehaviourHookError } from './chunk-WWP46AEF.js';
|
|
3
|
+
import { createGLTFLoader, SHARED_MODEL_RESOURCE_FLAG, applyTransform, findModelBone } from './chunk-JEPUCLZX.js';
|
|
4
|
+
import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, normalizeEnvironmentLighting, Environment, Postprocessing, TransformComponent, PhysicsComponent, setPhysicsLiveRef, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ScriptComponent, ScriptObjectComponent, AudioComponent, VideoComponent, UIPanelComponent, UITextComponent, UIButtonComponent, UIToggleComponent, UISliderComponent, ParentId, XRInteractableComponent, XRRigComponent, VRTeleportAreaComponent, XREnvironmentComponent, Name, resolveChrome, chromeBleed, resolveText, resolveToken, styleAssets, XRAnchorComponent, IKComponent, XRInteractorComponent, XRInteractorSideComponent, handPoseDefinitionFor, getHandPosePreset, XRHandPoseComponent } from './chunk-JNYPJB55.js';
|
|
5
5
|
import { __name } from './chunk-XE4OXN2W.js';
|
|
6
|
-
import * as
|
|
6
|
+
import * as THREE26 from 'three';
|
|
7
7
|
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
|
|
8
8
|
import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory.js';
|
|
9
9
|
import { XRHandModelFactory } from 'three/examples/jsm/webxr/XRHandModelFactory.js';
|
|
@@ -139,7 +139,7 @@ function transitionToClip(runtime, nextClipId, crossFadeDuration) {
|
|
|
139
139
|
}
|
|
140
140
|
__name(transitionToClip, "transitionToClip");
|
|
141
141
|
function applyActionState(action, component, paused, shouldLoop) {
|
|
142
|
-
const loopMode = shouldLoop ?
|
|
142
|
+
const loopMode = shouldLoop ? THREE26.LoopRepeat : THREE26.LoopOnce;
|
|
143
143
|
const repetitions = shouldLoop ? Infinity : 1;
|
|
144
144
|
action.setLoop(loopMode, repetitions);
|
|
145
145
|
action.clampWhenFinished = !shouldLoop;
|
|
@@ -312,7 +312,7 @@ var _AnimationSystem = class _AnimationSystem {
|
|
|
312
312
|
if (runtime) {
|
|
313
313
|
stopAllActions(runtime);
|
|
314
314
|
}
|
|
315
|
-
const mixer = new
|
|
315
|
+
const mixer = new THREE26.AnimationMixer(root);
|
|
316
316
|
const entries2 = readRuntimeClipEntries(animation);
|
|
317
317
|
const indexedActions = createActions(mixer, entries2);
|
|
318
318
|
runtime = {
|
|
@@ -438,11 +438,11 @@ function normalizeOrthoBounds(component) {
|
|
|
438
438
|
}
|
|
439
439
|
__name(normalizeOrthoBounds, "normalizeOrthoBounds");
|
|
440
440
|
function isPerspectiveCamera(camera) {
|
|
441
|
-
return camera instanceof
|
|
441
|
+
return camera instanceof THREE26.PerspectiveCamera;
|
|
442
442
|
}
|
|
443
443
|
__name(isPerspectiveCamera, "isPerspectiveCamera");
|
|
444
444
|
function isOrthographicCamera(camera) {
|
|
445
|
-
return camera instanceof
|
|
445
|
+
return camera instanceof THREE26.OrthographicCamera;
|
|
446
446
|
}
|
|
447
447
|
__name(isOrthographicCamera, "isOrthographicCamera");
|
|
448
448
|
function readWindowAspect() {
|
|
@@ -496,7 +496,7 @@ var _CameraSyncSystem = class _CameraSyncSystem {
|
|
|
496
496
|
continue;
|
|
497
497
|
}
|
|
498
498
|
const camera = objectRef.object;
|
|
499
|
-
if (!(camera instanceof
|
|
499
|
+
if (!(camera instanceof THREE26.Camera)) {
|
|
500
500
|
continue;
|
|
501
501
|
}
|
|
502
502
|
if (xrCamera !== null && camera === xrCamera) {
|
|
@@ -561,8 +561,8 @@ var ObjectVisibilitySystem = _ObjectVisibilitySystem;
|
|
|
561
561
|
function getUrlExtension(url) {
|
|
562
562
|
const path = url.split(/[?#]/)[0] ?? "";
|
|
563
563
|
const lastSegment = path.split("/").pop() ?? "";
|
|
564
|
-
const
|
|
565
|
-
return
|
|
564
|
+
const dot2 = lastSegment.lastIndexOf(".");
|
|
565
|
+
return dot2 >= 0 ? lastSegment.slice(dot2 + 1).toLowerCase() : "";
|
|
566
566
|
}
|
|
567
567
|
__name(getUrlExtension, "getUrlExtension");
|
|
568
568
|
async function loadEquirectTexture(url) {
|
|
@@ -575,10 +575,10 @@ async function loadEquirectTexture(url) {
|
|
|
575
575
|
const { EXRLoader } = await import('three/examples/jsm/loaders/EXRLoader.js');
|
|
576
576
|
texture = await new EXRLoader().loadAsync(url);
|
|
577
577
|
} else {
|
|
578
|
-
texture = await new
|
|
579
|
-
texture.colorSpace =
|
|
578
|
+
texture = await new THREE26.TextureLoader().loadAsync(url);
|
|
579
|
+
texture.colorSpace = THREE26.SRGBColorSpace;
|
|
580
580
|
}
|
|
581
|
-
texture.mapping =
|
|
581
|
+
texture.mapping = THREE26.EquirectangularReflectionMapping;
|
|
582
582
|
texture.needsUpdate = true;
|
|
583
583
|
return texture;
|
|
584
584
|
}
|
|
@@ -587,13 +587,13 @@ var rendererStates = /* @__PURE__ */ new WeakMap();
|
|
|
587
587
|
function toThreeToneMapping(mode) {
|
|
588
588
|
switch (mode) {
|
|
589
589
|
case "aces":
|
|
590
|
-
return
|
|
590
|
+
return THREE26.ACESFilmicToneMapping;
|
|
591
591
|
case "agx":
|
|
592
|
-
return
|
|
592
|
+
return THREE26.AgXToneMapping;
|
|
593
593
|
case "neutral":
|
|
594
|
-
return
|
|
594
|
+
return THREE26.NeutralToneMapping;
|
|
595
595
|
default:
|
|
596
|
-
return
|
|
596
|
+
return THREE26.NoToneMapping;
|
|
597
597
|
}
|
|
598
598
|
}
|
|
599
599
|
__name(toThreeToneMapping, "toThreeToneMapping");
|
|
@@ -614,7 +614,7 @@ function setRendererToneMappingSource(renderer, source, request) {
|
|
|
614
614
|
if (request === null) return;
|
|
615
615
|
state = {
|
|
616
616
|
baseline: {
|
|
617
|
-
toneMapping: target.toneMapping ??
|
|
617
|
+
toneMapping: target.toneMapping ?? THREE26.NoToneMapping,
|
|
618
618
|
exposure: typeof target.toneMappingExposure === "number" ? target.toneMappingExposure : 1
|
|
619
619
|
},
|
|
620
620
|
environment: null,
|
|
@@ -645,7 +645,7 @@ var MIN_DENSITY = 0;
|
|
|
645
645
|
function createGradientTexture(effect, colors) {
|
|
646
646
|
if (typeof document === "undefined") {
|
|
647
647
|
const pixel = new Uint8Array([30, 30, 30, 255]);
|
|
648
|
-
const fallback = new
|
|
648
|
+
const fallback = new THREE26.DataTexture(pixel, 1, 1, THREE26.RGBAFormat);
|
|
649
649
|
fallback.needsUpdate = true;
|
|
650
650
|
return fallback;
|
|
651
651
|
}
|
|
@@ -654,7 +654,7 @@ function createGradientTexture(effect, colors) {
|
|
|
654
654
|
canvas.height = 512;
|
|
655
655
|
const context = canvas.getContext("2d");
|
|
656
656
|
if (!context) {
|
|
657
|
-
const fallback = new
|
|
657
|
+
const fallback = new THREE26.CanvasTexture(canvas);
|
|
658
658
|
fallback.needsUpdate = true;
|
|
659
659
|
return fallback;
|
|
660
660
|
}
|
|
@@ -682,8 +682,8 @@ function createGradientTexture(effect, colors) {
|
|
|
682
682
|
context.fillRect(0, 0, 512, 512);
|
|
683
683
|
context.globalCompositeOperation = "source-over";
|
|
684
684
|
}
|
|
685
|
-
const texture = new
|
|
686
|
-
texture.colorSpace =
|
|
685
|
+
const texture = new THREE26.CanvasTexture(canvas);
|
|
686
|
+
texture.colorSpace = THREE26.SRGBColorSpace;
|
|
687
687
|
texture.needsUpdate = true;
|
|
688
688
|
return texture;
|
|
689
689
|
}
|
|
@@ -700,7 +700,7 @@ function readRenderer(world) {
|
|
|
700
700
|
__name(readRenderer, "readRenderer");
|
|
701
701
|
var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
|
|
702
702
|
constructor(scene) {
|
|
703
|
-
this.textureLoader = new
|
|
703
|
+
this.textureLoader = new THREE26.TextureLoader();
|
|
704
704
|
/** `true` once an Environment entity has been seen (drives the reset path). */
|
|
705
705
|
this.hasEnvironment = false;
|
|
706
706
|
this.skyboxSignature = null;
|
|
@@ -784,7 +784,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
|
|
|
784
784
|
if (skybox.type === "color") {
|
|
785
785
|
this.disposeActiveTexture();
|
|
786
786
|
this.pendingImageUrl = null;
|
|
787
|
-
this.setSkyboxBackground(new
|
|
787
|
+
this.setSkyboxBackground(new THREE26.Color(skybox.color || "#1e1e1e"));
|
|
788
788
|
return;
|
|
789
789
|
}
|
|
790
790
|
if (skybox.type === "gradient") {
|
|
@@ -819,7 +819,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
|
|
|
819
819
|
return;
|
|
820
820
|
}
|
|
821
821
|
if (!equirect) {
|
|
822
|
-
texture.colorSpace =
|
|
822
|
+
texture.colorSpace = THREE26.SRGBColorSpace;
|
|
823
823
|
}
|
|
824
824
|
this.activeTexture = texture;
|
|
825
825
|
this.setSkyboxBackground(texture);
|
|
@@ -847,16 +847,16 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
|
|
|
847
847
|
this.scene.fog = null;
|
|
848
848
|
return;
|
|
849
849
|
}
|
|
850
|
-
const fogColor = new
|
|
850
|
+
const fogColor = new THREE26.Color(fog.color || "#1e1e1e");
|
|
851
851
|
if (fog.type === "linear") {
|
|
852
852
|
const near = Number.isFinite(fog.linear.near) ? fog.linear.near : 1;
|
|
853
853
|
const farCandidate = Number.isFinite(fog.linear.far) ? fog.linear.far : near + 10;
|
|
854
854
|
const far = Math.max(near + MIN_FOG_DELTA, farCandidate);
|
|
855
|
-
this.scene.fog = new
|
|
855
|
+
this.scene.fog = new THREE26.Fog(fogColor, near, far);
|
|
856
856
|
return;
|
|
857
857
|
}
|
|
858
858
|
const density = Number.isFinite(fog.exponential.density) ? Math.max(MIN_DENSITY, fog.exponential.density) : 2e-3;
|
|
859
|
-
this.scene.fog = new
|
|
859
|
+
this.scene.fog = new THREE26.FogExp2(fogColor, density);
|
|
860
860
|
}
|
|
861
861
|
// ── Image-based lighting ────────────────────────────────────────────────
|
|
862
862
|
disposeEnvResources() {
|
|
@@ -918,7 +918,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
|
|
|
918
918
|
if (!renderer || getRendererKindOf(renderer) === "webgpu") return null;
|
|
919
919
|
let generator = null;
|
|
920
920
|
try {
|
|
921
|
-
generator = new
|
|
921
|
+
generator = new THREE26.PMREMGenerator(renderer);
|
|
922
922
|
return generator.fromEquirectangular(texture);
|
|
923
923
|
} catch (error) {
|
|
924
924
|
console.warn(
|
|
@@ -1213,7 +1213,7 @@ function computeColliderState(colliderValues, object) {
|
|
|
1213
1213
|
if (!object) {
|
|
1214
1214
|
return colliderValues;
|
|
1215
1215
|
}
|
|
1216
|
-
const scale = new
|
|
1216
|
+
const scale = new THREE26.Vector3();
|
|
1217
1217
|
object.getWorldScale(scale);
|
|
1218
1218
|
return {
|
|
1219
1219
|
...colliderValues,
|
|
@@ -1264,8 +1264,8 @@ function createColliderDesc(RAPIER, values, triMeshData) {
|
|
|
1264
1264
|
values.offsetPosition.y,
|
|
1265
1265
|
values.offsetPosition.z
|
|
1266
1266
|
);
|
|
1267
|
-
const offsetQuaternion = new
|
|
1268
|
-
new
|
|
1267
|
+
const offsetQuaternion = new THREE26.Quaternion().setFromEuler(
|
|
1268
|
+
new THREE26.Euler(
|
|
1269
1269
|
values.offsetRotation.x,
|
|
1270
1270
|
values.offsetRotation.y,
|
|
1271
1271
|
values.offsetRotation.z
|
|
@@ -1280,17 +1280,17 @@ function collectTriMeshParts(object) {
|
|
|
1280
1280
|
return null;
|
|
1281
1281
|
}
|
|
1282
1282
|
object.updateWorldMatrix(true, true);
|
|
1283
|
-
const worldScale = new
|
|
1283
|
+
const worldScale = new THREE26.Vector3();
|
|
1284
1284
|
object.getWorldScale(worldScale);
|
|
1285
1285
|
const scale = {
|
|
1286
1286
|
x: Math.abs(worldScale.x) || 1,
|
|
1287
1287
|
y: Math.abs(worldScale.y) || 1,
|
|
1288
1288
|
z: Math.abs(worldScale.z) || 1
|
|
1289
1289
|
};
|
|
1290
|
-
const worldToObject = new
|
|
1290
|
+
const worldToObject = new THREE26.Matrix4().copy(object.matrixWorld).invert();
|
|
1291
1291
|
const parts = [];
|
|
1292
1292
|
object.traverse((child) => {
|
|
1293
|
-
if (!(child instanceof
|
|
1293
|
+
if (!(child instanceof THREE26.Mesh) || !child.geometry) {
|
|
1294
1294
|
return;
|
|
1295
1295
|
}
|
|
1296
1296
|
const geometry = child.geometry;
|
|
@@ -1307,7 +1307,7 @@ function collectTriMeshParts(object) {
|
|
|
1307
1307
|
if (indexCount < 3) {
|
|
1308
1308
|
return;
|
|
1309
1309
|
}
|
|
1310
|
-
const relativeMatrix = new
|
|
1310
|
+
const relativeMatrix = new THREE26.Matrix4().multiplyMatrices(
|
|
1311
1311
|
worldToObject,
|
|
1312
1312
|
child.matrixWorld
|
|
1313
1313
|
);
|
|
@@ -1348,7 +1348,7 @@ function createTriMeshData(collected) {
|
|
|
1348
1348
|
}
|
|
1349
1349
|
const vertices = new Float32Array(vertexTotal * 3);
|
|
1350
1350
|
const indices = new Uint32Array(indexTotal);
|
|
1351
|
-
const point = new
|
|
1351
|
+
const point = new THREE26.Vector3();
|
|
1352
1352
|
let vertexOffset = 0;
|
|
1353
1353
|
let indexOffset = 0;
|
|
1354
1354
|
for (const part of parts) {
|
|
@@ -1380,8 +1380,8 @@ function createTriMeshData(collected) {
|
|
|
1380
1380
|
}
|
|
1381
1381
|
__name(createTriMeshData, "createTriMeshData");
|
|
1382
1382
|
function syncBodyFromTransform(body, transform) {
|
|
1383
|
-
const quaternion = new
|
|
1384
|
-
new
|
|
1383
|
+
const quaternion = new THREE26.Quaternion().setFromEuler(
|
|
1384
|
+
new THREE26.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
|
|
1385
1385
|
);
|
|
1386
1386
|
body.setTranslation(
|
|
1387
1387
|
{
|
|
@@ -1408,8 +1408,8 @@ function syncTransformFromBody(transform, body) {
|
|
|
1408
1408
|
transform.position.x = position.x;
|
|
1409
1409
|
transform.position.y = position.y;
|
|
1410
1410
|
transform.position.z = position.z;
|
|
1411
|
-
const euler = new
|
|
1412
|
-
new
|
|
1411
|
+
const euler = new THREE26.Euler().setFromQuaternion(
|
|
1412
|
+
new THREE26.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
|
|
1413
1413
|
);
|
|
1414
1414
|
transform.rotation.x = euler.x;
|
|
1415
1415
|
transform.rotation.y = euler.y;
|
|
@@ -1522,8 +1522,8 @@ var _PhysicsSyncSystem = class _PhysicsSyncSystem {
|
|
|
1522
1522
|
transform.position.y,
|
|
1523
1523
|
transform.position.z
|
|
1524
1524
|
);
|
|
1525
|
-
const quaternion = new
|
|
1526
|
-
new
|
|
1525
|
+
const quaternion = new THREE26.Quaternion().setFromEuler(
|
|
1526
|
+
new THREE26.Euler(
|
|
1527
1527
|
transform.rotation.x,
|
|
1528
1528
|
transform.rotation.y,
|
|
1529
1529
|
transform.rotation.z
|
|
@@ -2254,7 +2254,7 @@ function applyLightValues(lightComponent, rendererKind) {
|
|
|
2254
2254
|
values.castShadow
|
|
2255
2255
|
);
|
|
2256
2256
|
}
|
|
2257
|
-
if (light instanceof
|
|
2257
|
+
if (light instanceof THREE26.PointLight) {
|
|
2258
2258
|
if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
|
|
2259
2259
|
light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
|
|
2260
2260
|
}
|
|
@@ -2262,7 +2262,7 @@ function applyLightValues(lightComponent, rendererKind) {
|
|
|
2262
2262
|
light.decay = Math.max(0, values.decay);
|
|
2263
2263
|
}
|
|
2264
2264
|
}
|
|
2265
|
-
if (light instanceof
|
|
2265
|
+
if (light instanceof THREE26.SpotLight) {
|
|
2266
2266
|
if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
|
|
2267
2267
|
light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
|
|
2268
2268
|
}
|
|
@@ -2276,7 +2276,7 @@ function applyLightValues(lightComponent, rendererKind) {
|
|
|
2276
2276
|
light.penumbra = Math.max(0, Math.min(1, values.penumbra));
|
|
2277
2277
|
}
|
|
2278
2278
|
}
|
|
2279
|
-
if (light instanceof
|
|
2279
|
+
if (light instanceof THREE26.RectAreaLight) {
|
|
2280
2280
|
if (typeof values.width === "number" && Number.isFinite(values.width)) {
|
|
2281
2281
|
light.width = Math.max(MIN_AREA_SIZE, values.width);
|
|
2282
2282
|
}
|
|
@@ -2340,15 +2340,15 @@ function resolveMaterialPropertyKey(key) {
|
|
|
2340
2340
|
__name(resolveMaterialPropertyKey, "resolveMaterialPropertyKey");
|
|
2341
2341
|
function createMaterialByType(type) {
|
|
2342
2342
|
if (type === "basic") {
|
|
2343
|
-
return new
|
|
2343
|
+
return new THREE26.MeshBasicMaterial();
|
|
2344
2344
|
}
|
|
2345
2345
|
if (type === "phong") {
|
|
2346
|
-
return new
|
|
2346
|
+
return new THREE26.MeshPhongMaterial();
|
|
2347
2347
|
}
|
|
2348
2348
|
if (type === "physical") {
|
|
2349
|
-
return new
|
|
2349
|
+
return new THREE26.MeshPhysicalMaterial();
|
|
2350
2350
|
}
|
|
2351
|
-
return new
|
|
2351
|
+
return new THREE26.MeshStandardMaterial();
|
|
2352
2352
|
}
|
|
2353
2353
|
__name(createMaterialByType, "createMaterialByType");
|
|
2354
2354
|
function replaceMaterialAcrossObject(object, previous, next) {
|
|
@@ -2407,12 +2407,12 @@ function applyTextureFiltering(material, filtering) {
|
|
|
2407
2407
|
const target = material;
|
|
2408
2408
|
for (const slot of materialTextureSlots) {
|
|
2409
2409
|
const texture = target[slot];
|
|
2410
|
-
if (!texture || !(texture instanceof
|
|
2410
|
+
if (!texture || !(texture instanceof THREE26.Texture)) {
|
|
2411
2411
|
continue;
|
|
2412
2412
|
}
|
|
2413
2413
|
const useMipmaps = texture.generateMipmaps !== false;
|
|
2414
|
-
texture.magFilter = sharp ?
|
|
2415
|
-
texture.minFilter = useMipmaps ? sharp ?
|
|
2414
|
+
texture.magFilter = sharp ? THREE26.NearestFilter : THREE26.LinearFilter;
|
|
2415
|
+
texture.minFilter = useMipmaps ? sharp ? THREE26.NearestMipmapNearestFilter : THREE26.LinearMipmapLinearFilter : sharp ? THREE26.NearestFilter : THREE26.LinearFilter;
|
|
2416
2416
|
texture.needsUpdate = true;
|
|
2417
2417
|
}
|
|
2418
2418
|
material.needsUpdate = true;
|
|
@@ -2422,12 +2422,12 @@ function setTextureMipmaps(material, enabled) {
|
|
|
2422
2422
|
const target = material;
|
|
2423
2423
|
for (const slot of materialTextureSlots) {
|
|
2424
2424
|
const texture = target[slot];
|
|
2425
|
-
if (!texture || !(texture instanceof
|
|
2425
|
+
if (!texture || !(texture instanceof THREE26.Texture)) {
|
|
2426
2426
|
continue;
|
|
2427
2427
|
}
|
|
2428
2428
|
texture.generateMipmaps = enabled;
|
|
2429
|
-
const sharp = texture.magFilter ===
|
|
2430
|
-
texture.minFilter = enabled ? sharp ?
|
|
2429
|
+
const sharp = texture.magFilter === THREE26.NearestFilter;
|
|
2430
|
+
texture.minFilter = enabled ? sharp ? THREE26.NearestMipmapNearestFilter : THREE26.LinearMipmapLinearFilter : sharp ? THREE26.NearestFilter : THREE26.LinearFilter;
|
|
2431
2431
|
texture.needsUpdate = true;
|
|
2432
2432
|
}
|
|
2433
2433
|
material.needsUpdate = true;
|
|
@@ -2438,7 +2438,7 @@ function assignMaterialTexture(material, rawKey, url, textureCache) {
|
|
|
2438
2438
|
const key = resolveMaterialPropertyKey(rawKey);
|
|
2439
2439
|
let texture = textureCache.get(url);
|
|
2440
2440
|
if (!texture) {
|
|
2441
|
-
texture = new
|
|
2441
|
+
texture = new THREE26.TextureLoader().load(url);
|
|
2442
2442
|
textureCache.set(url, texture);
|
|
2443
2443
|
}
|
|
2444
2444
|
target[key] = texture;
|
|
@@ -2476,7 +2476,7 @@ function applyMaterialState(material, value, textureCache) {
|
|
|
2476
2476
|
}
|
|
2477
2477
|
target.side = value.side;
|
|
2478
2478
|
target.blending = value.blending;
|
|
2479
|
-
target.premultipliedAlpha = value.blending ===
|
|
2479
|
+
target.premultipliedAlpha = value.blending === THREE26.MultiplyBlending || value.blending === THREE26.SubtractiveBlending;
|
|
2480
2480
|
target.depthTest = value.depthTest;
|
|
2481
2481
|
target.depthWrite = value.depthWrite;
|
|
2482
2482
|
target.wireframe = value.wireframe;
|
|
@@ -2637,12 +2637,12 @@ function resolvePrimaryMesh(object) {
|
|
|
2637
2637
|
if (!object) {
|
|
2638
2638
|
return null;
|
|
2639
2639
|
}
|
|
2640
|
-
if (object instanceof
|
|
2640
|
+
if (object instanceof THREE26.Mesh) {
|
|
2641
2641
|
return object;
|
|
2642
2642
|
}
|
|
2643
2643
|
let found = null;
|
|
2644
2644
|
object.traverse((child) => {
|
|
2645
|
-
if (!found && child instanceof
|
|
2645
|
+
if (!found && child instanceof THREE26.Mesh) {
|
|
2646
2646
|
found = child;
|
|
2647
2647
|
}
|
|
2648
2648
|
});
|
|
@@ -2663,22 +2663,22 @@ function applyGeometry(component) {
|
|
|
2663
2663
|
switch (component.kind) {
|
|
2664
2664
|
case "cube": {
|
|
2665
2665
|
const params = sanitized;
|
|
2666
|
-
nextGeometry = new
|
|
2666
|
+
nextGeometry = new THREE26.BoxGeometry(params.width, params.height, params.depth);
|
|
2667
2667
|
break;
|
|
2668
2668
|
}
|
|
2669
2669
|
case "plane": {
|
|
2670
2670
|
const params = sanitized;
|
|
2671
|
-
nextGeometry = new
|
|
2671
|
+
nextGeometry = new THREE26.PlaneGeometry(params.width, params.height);
|
|
2672
2672
|
break;
|
|
2673
2673
|
}
|
|
2674
2674
|
case "sphere": {
|
|
2675
2675
|
const params = sanitized;
|
|
2676
|
-
nextGeometry = new
|
|
2676
|
+
nextGeometry = new THREE26.SphereGeometry(params.radius, 24, 24);
|
|
2677
2677
|
break;
|
|
2678
2678
|
}
|
|
2679
2679
|
case "cylinder": {
|
|
2680
2680
|
const params = sanitized;
|
|
2681
|
-
nextGeometry = new
|
|
2681
|
+
nextGeometry = new THREE26.CylinderGeometry(
|
|
2682
2682
|
params.radius,
|
|
2683
2683
|
params.radius,
|
|
2684
2684
|
params.height,
|
|
@@ -2688,7 +2688,7 @@ function applyGeometry(component) {
|
|
|
2688
2688
|
}
|
|
2689
2689
|
case "capsule": {
|
|
2690
2690
|
const params = sanitized;
|
|
2691
|
-
nextGeometry = new
|
|
2691
|
+
nextGeometry = new THREE26.CapsuleGeometry(params.radius, params.height, 4, 8);
|
|
2692
2692
|
break;
|
|
2693
2693
|
}
|
|
2694
2694
|
default:
|
|
@@ -2704,7 +2704,7 @@ function applyShadowFlags(component) {
|
|
|
2704
2704
|
return;
|
|
2705
2705
|
}
|
|
2706
2706
|
component.object.traverse((child) => {
|
|
2707
|
-
if (child instanceof
|
|
2707
|
+
if (child instanceof THREE26.Mesh) {
|
|
2708
2708
|
child.castShadow = component.castShadow;
|
|
2709
2709
|
child.receiveShadow = component.receiveShadow;
|
|
2710
2710
|
}
|
|
@@ -2780,35 +2780,35 @@ function buildGeometry(component) {
|
|
|
2780
2780
|
switch (component.meshKind) {
|
|
2781
2781
|
case "cube": {
|
|
2782
2782
|
const params = p;
|
|
2783
|
-
return new
|
|
2783
|
+
return new THREE26.BoxGeometry(params.width, params.height, params.depth);
|
|
2784
2784
|
}
|
|
2785
2785
|
case "plane": {
|
|
2786
2786
|
const params = p;
|
|
2787
|
-
return new
|
|
2787
|
+
return new THREE26.PlaneGeometry(params.width, params.height);
|
|
2788
2788
|
}
|
|
2789
2789
|
case "sphere": {
|
|
2790
2790
|
const params = p;
|
|
2791
|
-
return new
|
|
2791
|
+
return new THREE26.SphereGeometry(params.radius, 24, 24);
|
|
2792
2792
|
}
|
|
2793
2793
|
case "cylinder": {
|
|
2794
2794
|
const params = p;
|
|
2795
|
-
return new
|
|
2795
|
+
return new THREE26.CylinderGeometry(params.radius, params.radius, params.height, 20);
|
|
2796
2796
|
}
|
|
2797
2797
|
case "capsule": {
|
|
2798
2798
|
const params = p;
|
|
2799
|
-
return new
|
|
2799
|
+
return new THREE26.CapsuleGeometry(params.radius, params.height, 4, 8);
|
|
2800
2800
|
}
|
|
2801
2801
|
default:
|
|
2802
|
-
return new
|
|
2802
|
+
return new THREE26.BoxGeometry(1, 1, 1);
|
|
2803
2803
|
}
|
|
2804
2804
|
}
|
|
2805
2805
|
__name(buildGeometry, "buildGeometry");
|
|
2806
|
-
var _position = new
|
|
2807
|
-
var _quaternion = new
|
|
2808
|
-
var _euler = new
|
|
2809
|
-
var _scale = new
|
|
2810
|
-
var _matrix = new
|
|
2811
|
-
var _modelMatrix = new
|
|
2806
|
+
var _position = new THREE26.Vector3();
|
|
2807
|
+
var _quaternion = new THREE26.Quaternion();
|
|
2808
|
+
var _euler = new THREE26.Euler();
|
|
2809
|
+
var _scale = new THREE26.Vector3();
|
|
2810
|
+
var _matrix = new THREE26.Matrix4();
|
|
2811
|
+
var _modelMatrix = new THREE26.Matrix4();
|
|
2812
2812
|
function instanceTransformFromComponent(transform, out) {
|
|
2813
2813
|
_position.set(transform.position.x, transform.position.y, transform.position.z);
|
|
2814
2814
|
_euler.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, "XYZ");
|
|
@@ -2890,9 +2890,9 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
|
|
|
2890
2890
|
const instanceCount = comp.instanceEntityIds.length;
|
|
2891
2891
|
const geometrySignature = comp.meshKind === "model" ? `model:${comp.modelPath}:${instanceCount}` : `${comp.meshKind}:${JSON.stringify(comp.meshParameters)}:${instanceCount}`;
|
|
2892
2892
|
if (comp.instancedMesh === null) {
|
|
2893
|
-
const
|
|
2894
|
-
if (
|
|
2895
|
-
comp.instancedMesh =
|
|
2893
|
+
const tracked2 = this.trackedMeshes.get(entityId);
|
|
2894
|
+
if (tracked2) {
|
|
2895
|
+
comp.instancedMesh = tracked2;
|
|
2896
2896
|
}
|
|
2897
2897
|
}
|
|
2898
2898
|
const pendingLoadSignature = this.loadingSignatures.get(entityId);
|
|
@@ -2961,7 +2961,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
|
|
|
2961
2961
|
const sourceMaterial = Array.isArray(meshChild.material) ? meshChild.material.map((m) => m.clone()) : meshChild.material.clone();
|
|
2962
2962
|
meshChild.updateWorldMatrix(true, false);
|
|
2963
2963
|
const localMatrix = meshChild.matrixWorld.clone();
|
|
2964
|
-
const instancedMesh2 = new
|
|
2964
|
+
const instancedMesh2 = new THREE26.InstancedMesh(
|
|
2965
2965
|
geometry2,
|
|
2966
2966
|
Array.isArray(sourceMaterial) ? sourceMaterial : sourceMaterial,
|
|
2967
2967
|
count2
|
|
@@ -2986,7 +2986,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
|
|
|
2986
2986
|
this.loadingSignatures.delete(targetEntityId);
|
|
2987
2987
|
return;
|
|
2988
2988
|
}
|
|
2989
|
-
const group = new
|
|
2989
|
+
const group = new THREE26.Group();
|
|
2990
2990
|
for (const entry of entries) {
|
|
2991
2991
|
group.add(entry.instancedMesh);
|
|
2992
2992
|
}
|
|
@@ -3004,8 +3004,8 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
|
|
|
3004
3004
|
}
|
|
3005
3005
|
const count = instanceCount;
|
|
3006
3006
|
const geometry = buildGeometry(comp);
|
|
3007
|
-
const material = new
|
|
3008
|
-
const instancedMesh = new
|
|
3007
|
+
const material = new THREE26.MeshStandardMaterial({ color: "#ffffff" });
|
|
3008
|
+
const instancedMesh = new THREE26.InstancedMesh(geometry, material, count);
|
|
3009
3009
|
instancedMesh.castShadow = comp.castShadow;
|
|
3010
3010
|
instancedMesh.receiveShadow = comp.receiveShadow;
|
|
3011
3011
|
for (let i = 0; i < count; i++) {
|
|
@@ -3213,8 +3213,8 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
3213
3213
|
const retryDelay = options?.errorRetryDelay;
|
|
3214
3214
|
this.errorRetryDelay = typeof retryDelay === "number" && Number.isFinite(retryDelay) ? Math.max(0, retryDelay) : DEFAULT_SCRIPT_ERROR_RETRY_DELAY;
|
|
3215
3215
|
this.selectionCtx = selectionContext ?? null;
|
|
3216
|
-
this.raycaster = new
|
|
3217
|
-
this.ndcPointer = new
|
|
3216
|
+
this.raycaster = new THREE26.Raycaster();
|
|
3217
|
+
this.ndcPointer = new THREE26.Vector2();
|
|
3218
3218
|
if (this.selectionCtx) {
|
|
3219
3219
|
this.selectionCtx.domElement.addEventListener("pointerdown", this.onPointerDown);
|
|
3220
3220
|
this.selectionCtx.domElement.addEventListener("pointerup", this.onPointerUp);
|
|
@@ -3658,7 +3658,7 @@ function disposeBuiltObject(root) {
|
|
|
3658
3658
|
for (const mat of materials) {
|
|
3659
3659
|
if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
|
|
3660
3660
|
for (const value of Object.values(mat)) {
|
|
3661
|
-
if (value instanceof
|
|
3661
|
+
if (value instanceof THREE26.Texture) value.dispose();
|
|
3662
3662
|
}
|
|
3663
3663
|
mat.dispose?.();
|
|
3664
3664
|
}
|
|
@@ -4259,7 +4259,7 @@ var _AudioSystem = class _AudioSystem {
|
|
|
4259
4259
|
if (!prev || prev.volume !== opts.volume) {
|
|
4260
4260
|
sound.setVolume(opts.volume);
|
|
4261
4261
|
}
|
|
4262
|
-
if (opts.positional && sound instanceof
|
|
4262
|
+
if (opts.positional && sound instanceof THREE26.PositionalAudio) {
|
|
4263
4263
|
if (!prev || prev.refDistance !== opts.refDistance) {
|
|
4264
4264
|
sound.setRefDistance(opts.refDistance);
|
|
4265
4265
|
}
|
|
@@ -4399,7 +4399,7 @@ var _VideoSystem = class _VideoSystem {
|
|
|
4399
4399
|
spill: opts.spill
|
|
4400
4400
|
});
|
|
4401
4401
|
}
|
|
4402
|
-
if (opts.positional && component.audioNode instanceof
|
|
4402
|
+
if (opts.positional && component.audioNode instanceof THREE26.PositionalAudio) {
|
|
4403
4403
|
const posAudio = component.audioNode;
|
|
4404
4404
|
if (!prev || prev.refDistance !== opts.refDistance) {
|
|
4405
4405
|
posAudio.setRefDistance(opts.refDistance);
|
|
@@ -4439,8 +4439,8 @@ function blankState(source) {
|
|
|
4439
4439
|
handedness: handednessOf(source),
|
|
4440
4440
|
kind: kindOf(source),
|
|
4441
4441
|
connected: true,
|
|
4442
|
-
rayOrigin: new
|
|
4443
|
-
rayDirection: new
|
|
4442
|
+
rayOrigin: new THREE26.Vector3(),
|
|
4443
|
+
rayDirection: new THREE26.Vector3(0, 0, -1),
|
|
4444
4444
|
gripPosition: null,
|
|
4445
4445
|
gripQuaternion: null,
|
|
4446
4446
|
select: false,
|
|
@@ -4466,7 +4466,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
|
|
|
4466
4466
|
}
|
|
4467
4467
|
if (spaces.length === 0) return null;
|
|
4468
4468
|
const target = existing ?? {};
|
|
4469
|
-
const matrix = new
|
|
4469
|
+
const matrix = new THREE26.Matrix4();
|
|
4470
4470
|
const buffer = spaces.length * 16 <= JOINT_MATRIX_BUFFER.length ? JOINT_MATRIX_BUFFER : new Float32Array(spaces.length * 16);
|
|
4471
4471
|
const fillPoses = frame.fillPoses;
|
|
4472
4472
|
if (typeof fillPoses === "function") {
|
|
@@ -4479,7 +4479,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
|
|
|
4479
4479
|
if (filled) {
|
|
4480
4480
|
for (let i = 0; i < names.length; i += 1) {
|
|
4481
4481
|
matrix.fromArray(buffer, i * 16).premultiply(rigMatrix);
|
|
4482
|
-
const vector = target[names[i]] ?? new
|
|
4482
|
+
const vector = target[names[i]] ?? new THREE26.Vector3();
|
|
4483
4483
|
vector.setFromMatrixPosition(matrix);
|
|
4484
4484
|
target[names[i]] = vector;
|
|
4485
4485
|
}
|
|
@@ -4497,7 +4497,7 @@ function readHandJoints(frame, hand, referenceSpace, rigMatrix, existing) {
|
|
|
4497
4497
|
continue;
|
|
4498
4498
|
}
|
|
4499
4499
|
matrix.fromArray(pose.transform.matrix).premultiply(rigMatrix);
|
|
4500
|
-
const vector = target[names[i]] ?? new
|
|
4500
|
+
const vector = target[names[i]] ?? new THREE26.Vector3();
|
|
4501
4501
|
vector.setFromMatrixPosition(matrix);
|
|
4502
4502
|
target[names[i]] = vector;
|
|
4503
4503
|
anyTracked = true;
|
|
@@ -4509,7 +4509,7 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
4509
4509
|
constructor() {
|
|
4510
4510
|
this.records = /* @__PURE__ */ new Map();
|
|
4511
4511
|
/** Reference-space → world matrix, rebuilt each frame from the XR rig. */
|
|
4512
|
-
this.referenceToWorld = new
|
|
4512
|
+
this.referenceToWorld = new THREE26.Matrix4();
|
|
4513
4513
|
this.session = null;
|
|
4514
4514
|
this.onSelectStart = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectStart"), "onSelectStart");
|
|
4515
4515
|
this.onSelectEnd = /* @__PURE__ */ __name((event) => this.mark(event, "pendingSelectEnd"), "onSelectEnd");
|
|
@@ -4607,19 +4607,19 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
4607
4607
|
if (frame && referenceSpace && source.targetRaySpace) {
|
|
4608
4608
|
const pose = frame.getPose(source.targetRaySpace, referenceSpace);
|
|
4609
4609
|
if (pose) {
|
|
4610
|
-
const m = new
|
|
4610
|
+
const m = new THREE26.Matrix4().fromArray(pose.transform.matrix).premultiply(rigMatrix);
|
|
4611
4611
|
state.rayOrigin.setFromMatrixPosition(m);
|
|
4612
4612
|
state.rayDirection.set(0, 0, -1).applyQuaternion(
|
|
4613
|
-
new
|
|
4613
|
+
new THREE26.Quaternion().setFromRotationMatrix(m)
|
|
4614
4614
|
).normalize();
|
|
4615
4615
|
}
|
|
4616
4616
|
}
|
|
4617
4617
|
if (frame && referenceSpace && source.gripSpace) {
|
|
4618
4618
|
const gripPose = frame.getPose(source.gripSpace, referenceSpace);
|
|
4619
4619
|
if (gripPose) {
|
|
4620
|
-
const m = new
|
|
4621
|
-
state.gripPosition ?? (state.gripPosition = new
|
|
4622
|
-
state.gripQuaternion ?? (state.gripQuaternion = new
|
|
4620
|
+
const m = new THREE26.Matrix4().fromArray(gripPose.transform.matrix).premultiply(rigMatrix);
|
|
4621
|
+
state.gripPosition ?? (state.gripPosition = new THREE26.Vector3());
|
|
4622
|
+
state.gripQuaternion ?? (state.gripQuaternion = new THREE26.Quaternion());
|
|
4623
4623
|
state.gripPosition.setFromMatrixPosition(m);
|
|
4624
4624
|
state.gripQuaternion.setFromRotationMatrix(m);
|
|
4625
4625
|
}
|
|
@@ -4721,6 +4721,51 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
4721
4721
|
};
|
|
4722
4722
|
__name(_XRInputSystem, "XRInputSystem");
|
|
4723
4723
|
var XRInputSystem = _XRInputSystem;
|
|
4724
|
+
|
|
4725
|
+
// core/ui/uiWidgetTree.ts
|
|
4726
|
+
var UI_PART_KEY = "__uiPart";
|
|
4727
|
+
function applyPartColor(mesh, tag) {
|
|
4728
|
+
const material = mesh.material;
|
|
4729
|
+
material.color.copy(tag.baseColor).multiplyScalar(tag.premultiplied ? tag.tint * tag.opacity : tag.tint);
|
|
4730
|
+
material.opacity = tag.opacity;
|
|
4731
|
+
}
|
|
4732
|
+
__name(applyPartColor, "applyPartColor");
|
|
4733
|
+
function isUiWidget(world, entityId) {
|
|
4734
|
+
return !!world.getComponent(entityId, UIPanelComponent) || !!world.getComponent(entityId, UITextComponent) || !!world.getComponent(entityId, UIButtonComponent) || !!world.getComponent(entityId, UIToggleComponent) || !!world.getComponent(entityId, UISliderComponent);
|
|
4735
|
+
}
|
|
4736
|
+
__name(isUiWidget, "isUiWidget");
|
|
4737
|
+
function isShownInScene(world, entityId) {
|
|
4738
|
+
let object = world.getComponent(entityId, Object3DRef)?.object ?? null;
|
|
4739
|
+
while (object) {
|
|
4740
|
+
if (!object.visible) return false;
|
|
4741
|
+
object = object.parent;
|
|
4742
|
+
}
|
|
4743
|
+
return true;
|
|
4744
|
+
}
|
|
4745
|
+
__name(isShownInScene, "isShownInScene");
|
|
4746
|
+
function nearestWidgetAncestor(world, entityId) {
|
|
4747
|
+
const visited = /* @__PURE__ */ new Set([entityId]);
|
|
4748
|
+
let current = entityId;
|
|
4749
|
+
for (; ; ) {
|
|
4750
|
+
const parentId = world.getComponent(current, ParentId)?.value;
|
|
4751
|
+
if (typeof parentId !== "number" || visited.has(parentId)) return null;
|
|
4752
|
+
if (isUiWidget(world, parentId)) return parentId;
|
|
4753
|
+
visited.add(parentId);
|
|
4754
|
+
current = parentId;
|
|
4755
|
+
}
|
|
4756
|
+
}
|
|
4757
|
+
__name(nearestWidgetAncestor, "nearestWidgetAncestor");
|
|
4758
|
+
function widgetTreeRoot(world, entityId) {
|
|
4759
|
+
const visited = /* @__PURE__ */ new Set([entityId]);
|
|
4760
|
+
let root = entityId;
|
|
4761
|
+
for (; ; ) {
|
|
4762
|
+
const parent = nearestWidgetAncestor(world, root);
|
|
4763
|
+
if (parent === null || visited.has(parent)) return root;
|
|
4764
|
+
visited.add(parent);
|
|
4765
|
+
root = parent;
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
__name(widgetTreeRoot, "widgetTreeRoot");
|
|
4724
4769
|
var VELOCITY_SAMPLES = 5;
|
|
4725
4770
|
var MAX_SAMPLE_AGE_SECONDS = 0.2;
|
|
4726
4771
|
var MAX_PLAUSIBLE_SPEED = 20;
|
|
@@ -4747,15 +4792,15 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
|
|
|
4747
4792
|
const fresh = this.samples.filter(
|
|
4748
4793
|
(sample) => now - sample.time <= MAX_SAMPLE_AGE_SECONDS
|
|
4749
4794
|
);
|
|
4750
|
-
if (fresh.length < 2) return new
|
|
4751
|
-
let best = new
|
|
4795
|
+
if (fresh.length < 2) return new THREE26.Vector3();
|
|
4796
|
+
let best = new THREE26.Vector3();
|
|
4752
4797
|
let bestSpeed = 0;
|
|
4753
4798
|
for (let i = 1; i < fresh.length; i += 1) {
|
|
4754
4799
|
const previous = fresh[i - 1];
|
|
4755
4800
|
const current = fresh[i];
|
|
4756
4801
|
const dt = current.time - previous.time;
|
|
4757
4802
|
if (dt <= 1e-5) continue;
|
|
4758
|
-
const velocity = new
|
|
4803
|
+
const velocity = new THREE26.Vector3().subVectors(current.position, previous.position).divideScalar(dt);
|
|
4759
4804
|
const speed = velocity.length();
|
|
4760
4805
|
if (speed > MAX_PLAUSIBLE_SPEED) continue;
|
|
4761
4806
|
if (speed > bestSpeed) {
|
|
@@ -4772,15 +4817,15 @@ var _ThrowVelocityTracker = class _ThrowVelocityTracker {
|
|
|
4772
4817
|
__name(_ThrowVelocityTracker, "ThrowVelocityTracker");
|
|
4773
4818
|
var ThrowVelocityTracker = _ThrowVelocityTracker;
|
|
4774
4819
|
function angularVelocityFrom(previous, current, deltaTime) {
|
|
4775
|
-
if (deltaTime <= 1e-5) return new
|
|
4820
|
+
if (deltaTime <= 1e-5) return new THREE26.Vector3();
|
|
4776
4821
|
const delta = current.clone().multiply(previous.clone().invert());
|
|
4777
4822
|
if (delta.w < 0) {
|
|
4778
4823
|
delta.set(-delta.x, -delta.y, -delta.z, -delta.w);
|
|
4779
4824
|
}
|
|
4780
|
-
const angle = 2 * Math.acos(
|
|
4825
|
+
const angle = 2 * Math.acos(THREE26.MathUtils.clamp(delta.w, -1, 1));
|
|
4781
4826
|
const sinHalf = Math.sqrt(Math.max(0, 1 - delta.w * delta.w));
|
|
4782
|
-
if (sinHalf < 1e-6 || angle < 1e-6) return new
|
|
4783
|
-
return new
|
|
4827
|
+
if (sinHalf < 1e-6 || angle < 1e-6) return new THREE26.Vector3();
|
|
4828
|
+
return new THREE26.Vector3(delta.x, delta.y, delta.z).divideScalar(sinHalf).multiplyScalar(angle / deltaTime);
|
|
4784
4829
|
}
|
|
4785
4830
|
__name(angularVelocityFrom, "angularVelocityFrom");
|
|
4786
4831
|
var MIN_HAND_SEPARATION = 0.06;
|
|
@@ -4788,7 +4833,7 @@ var MIN_ANCHOR_SEPARATION = 1e-3;
|
|
|
4788
4833
|
var SCALE_DEADZONE = 0.05;
|
|
4789
4834
|
function solveTwoHandTransform(primary, secondary, basis, options) {
|
|
4790
4835
|
const separation = primary.position.distanceTo(secondary.position);
|
|
4791
|
-
const anchorDelta = new
|
|
4836
|
+
const anchorDelta = new THREE26.Vector3().subVectors(
|
|
4792
4837
|
basis.secondaryLocal,
|
|
4793
4838
|
basis.primaryLocal
|
|
4794
4839
|
);
|
|
@@ -4812,8 +4857,8 @@ function solveTwoHandTransform(primary, secondary, basis, options) {
|
|
|
4812
4857
|
} else {
|
|
4813
4858
|
const axisLocal = anchorDelta.clone().normalize();
|
|
4814
4859
|
const currentAxis = axisLocal.clone().applyQuaternion(base).normalize();
|
|
4815
|
-
const desiredAxis = new
|
|
4816
|
-
const correction = new
|
|
4860
|
+
const desiredAxis = new THREE26.Vector3().subVectors(secondary.position, primary.position).normalize();
|
|
4861
|
+
const correction = new THREE26.Quaternion().setFromUnitVectors(
|
|
4817
4862
|
currentAxis,
|
|
4818
4863
|
desiredAxis
|
|
4819
4864
|
);
|
|
@@ -4828,11 +4873,11 @@ __name(solveTwoHandTransform, "solveTwoHandTransform");
|
|
|
4828
4873
|
// core/systems/XRInteractionSystem.ts
|
|
4829
4874
|
var RAYLESS_HOLD_DISTANCE = 0.5;
|
|
4830
4875
|
function quatFromEulerVec(r) {
|
|
4831
|
-
return new
|
|
4876
|
+
return new THREE26.Quaternion().setFromEuler(new THREE26.Euler(r.x, r.y, r.z));
|
|
4832
4877
|
}
|
|
4833
4878
|
__name(quatFromEulerVec, "quatFromEulerVec");
|
|
4834
4879
|
function writeEuler(target, q) {
|
|
4835
|
-
const euler = new
|
|
4880
|
+
const euler = new THREE26.Euler().setFromQuaternion(q);
|
|
4836
4881
|
target.x = euler.x;
|
|
4837
4882
|
target.y = euler.y;
|
|
4838
4883
|
target.z = euler.z;
|
|
@@ -4840,7 +4885,7 @@ function writeEuler(target, q) {
|
|
|
4840
4885
|
__name(writeEuler, "writeEuler");
|
|
4841
4886
|
var _XRInteractionSystem = class _XRInteractionSystem {
|
|
4842
4887
|
constructor(inputSystem) {
|
|
4843
|
-
this.raycaster = new
|
|
4888
|
+
this.raycaster = new THREE26.Raycaster();
|
|
4844
4889
|
this.grabs = /* @__PURE__ */ new Map();
|
|
4845
4890
|
this.hoveredEntityId = null;
|
|
4846
4891
|
/** Per-hand hover, with the hit distance so the ray can stop at the surface. */
|
|
@@ -4951,7 +4996,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
4951
4996
|
const hand = this.handPosition(input);
|
|
4952
4997
|
const handQuaternion = this.handQuaternion(input);
|
|
4953
4998
|
const objectQuaternion = quatFromEulerVec(transform.rotation);
|
|
4954
|
-
record.offset = new
|
|
4999
|
+
record.offset = new THREE26.Vector3(
|
|
4955
5000
|
transform.position.x - hand.x,
|
|
4956
5001
|
transform.position.y - hand.y,
|
|
4957
5002
|
transform.position.z - hand.z
|
|
@@ -4983,7 +5028,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
4983
5028
|
primary.record.twoHand = {
|
|
4984
5029
|
primaryLocal,
|
|
4985
5030
|
secondaryLocal,
|
|
4986
|
-
initialScale: new
|
|
5031
|
+
initialScale: new THREE26.Vector3(
|
|
4987
5032
|
transform.scale.x,
|
|
4988
5033
|
transform.scale.y,
|
|
4989
5034
|
transform.scale.z
|
|
@@ -5004,7 +5049,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5004
5049
|
/** World point → the object's UNSCALED local space. */
|
|
5005
5050
|
objectLocalPoint(transform, worldPoint) {
|
|
5006
5051
|
const local = worldPoint.clone().sub(
|
|
5007
|
-
new
|
|
5052
|
+
new THREE26.Vector3(
|
|
5008
5053
|
transform.position.x,
|
|
5009
5054
|
transform.position.y,
|
|
5010
5055
|
transform.position.z
|
|
@@ -5062,7 +5107,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5062
5107
|
);
|
|
5063
5108
|
if (!interactable2) continue;
|
|
5064
5109
|
if (interactable2.grabReach === "distance") continue;
|
|
5065
|
-
const position = new
|
|
5110
|
+
const position = new THREE26.Vector3();
|
|
5066
5111
|
entry.object.getWorldPosition(position);
|
|
5067
5112
|
const distance = position.distanceTo(hand);
|
|
5068
5113
|
if (distance <= interactable2.grabRadius && distance < nearestDistance) {
|
|
@@ -5094,6 +5139,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5094
5139
|
const interactable = world.getComponent(entityId, XRInteractableComponent);
|
|
5095
5140
|
if (!interactable?.enabled) continue;
|
|
5096
5141
|
if (!world.isEntityVisible(entityId)) continue;
|
|
5142
|
+
if (!isShownInScene(world, entityId)) continue;
|
|
5097
5143
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
5098
5144
|
if (object) {
|
|
5099
5145
|
out.push({ entityId, object, pointable: interactable.pointable });
|
|
@@ -5134,13 +5180,13 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5134
5180
|
this.holdersOf(entityId).map((holder) => holder.record.attachPointId).filter((id) => id !== null)
|
|
5135
5181
|
);
|
|
5136
5182
|
const hand = this.handPosition(input);
|
|
5137
|
-
const objectPosition = new
|
|
5183
|
+
const objectPosition = new THREE26.Vector3(
|
|
5138
5184
|
transform.position.x,
|
|
5139
5185
|
transform.position.y,
|
|
5140
5186
|
transform.position.z
|
|
5141
5187
|
);
|
|
5142
5188
|
const objectQuaternion = quatFromEulerVec(transform.rotation);
|
|
5143
|
-
const scale = new
|
|
5189
|
+
const scale = new THREE26.Vector3(
|
|
5144
5190
|
transform.scale.x,
|
|
5145
5191
|
transform.scale.y,
|
|
5146
5192
|
transform.scale.z
|
|
@@ -5151,7 +5197,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5151
5197
|
if (taken.has(point.id)) continue;
|
|
5152
5198
|
if (point.hand !== "any" && point.hand !== input.handedness) continue;
|
|
5153
5199
|
if (point.role !== "any" && point.role !== role) continue;
|
|
5154
|
-
const world3 = new
|
|
5200
|
+
const world3 = new THREE26.Vector3(
|
|
5155
5201
|
point.position.x,
|
|
5156
5202
|
point.position.y,
|
|
5157
5203
|
point.position.z
|
|
@@ -5174,21 +5220,21 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5174
5220
|
let offset;
|
|
5175
5221
|
let remoteDistance = 0;
|
|
5176
5222
|
if (remote) {
|
|
5177
|
-
const position = new
|
|
5223
|
+
const position = new THREE26.Vector3(
|
|
5178
5224
|
transform.position.x,
|
|
5179
5225
|
transform.position.y,
|
|
5180
5226
|
transform.position.z
|
|
5181
5227
|
);
|
|
5182
5228
|
remoteDistance = position.distanceTo(input.rayOrigin);
|
|
5183
|
-
offset = new
|
|
5229
|
+
offset = new THREE26.Vector3();
|
|
5184
5230
|
} else if (viaDistance) {
|
|
5185
|
-
offset = new
|
|
5231
|
+
offset = new THREE26.Vector3(
|
|
5186
5232
|
interactable.grabOffsetPosition.x,
|
|
5187
5233
|
interactable.grabOffsetPosition.y,
|
|
5188
5234
|
interactable.grabOffsetPosition.z
|
|
5189
5235
|
);
|
|
5190
5236
|
} else {
|
|
5191
|
-
offset = new
|
|
5237
|
+
offset = new THREE26.Vector3(
|
|
5192
5238
|
transform.position.x - hand.x,
|
|
5193
5239
|
transform.position.y - hand.y,
|
|
5194
5240
|
transform.position.z - hand.z
|
|
@@ -5215,7 +5261,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5215
5261
|
entityId,
|
|
5216
5262
|
role,
|
|
5217
5263
|
attachPointId: attachPoint?.id ?? null,
|
|
5218
|
-
attachLocal: attachPoint ? new
|
|
5264
|
+
attachLocal: attachPoint ? new THREE26.Vector3(
|
|
5219
5265
|
attachPoint.position.x,
|
|
5220
5266
|
attachPoint.position.y,
|
|
5221
5267
|
attachPoint.position.z
|
|
@@ -5224,8 +5270,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5224
5270
|
handRotationOffset,
|
|
5225
5271
|
twoHand: null,
|
|
5226
5272
|
offset,
|
|
5227
|
-
rotationOffset: new
|
|
5228
|
-
new
|
|
5273
|
+
rotationOffset: new THREE26.Quaternion().setFromEuler(
|
|
5274
|
+
new THREE26.Euler(
|
|
5229
5275
|
interactable.grabOffsetRotation.x,
|
|
5230
5276
|
interactable.grabOffsetRotation.y,
|
|
5231
5277
|
interactable.grabOffsetRotation.z
|
|
@@ -5236,7 +5282,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5236
5282
|
restoreBodyType,
|
|
5237
5283
|
tracker,
|
|
5238
5284
|
lastHandQuaternion: handQuaternion.clone(),
|
|
5239
|
-
angularVelocity: new
|
|
5285
|
+
angularVelocity: new THREE26.Vector3()
|
|
5240
5286
|
});
|
|
5241
5287
|
if (role === "primary") {
|
|
5242
5288
|
this.dispatch(world, entityId, "onGrab", (b) => b.onGrab(input));
|
|
@@ -5309,14 +5355,14 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5309
5355
|
const handQuaternion = this.handQuaternion(input);
|
|
5310
5356
|
const objectQuaternion = held.attachQuaternion ? handQuaternion.clone().multiply(held.rotationOffset).multiply(held.attachQuaternion.clone().invert()) : handQuaternion.clone().multiply(held.handRotationOffset);
|
|
5311
5357
|
if (held.remote) {
|
|
5312
|
-
const target = new
|
|
5358
|
+
const target = new THREE26.Vector3().copy(input.rayDirection).multiplyScalar(held.remoteDistance).add(input.rayOrigin);
|
|
5313
5359
|
transform.position.x = target.x;
|
|
5314
5360
|
transform.position.y = target.y;
|
|
5315
5361
|
transform.position.z = target.z;
|
|
5316
5362
|
writeEuler(transform.rotation, objectQuaternion);
|
|
5317
5363
|
} else if (held.attachLocal) {
|
|
5318
5364
|
const anchor = held.attachLocal.clone().multiply(
|
|
5319
|
-
new
|
|
5365
|
+
new THREE26.Vector3(
|
|
5320
5366
|
transform.scale.x,
|
|
5321
5367
|
transform.scale.y,
|
|
5322
5368
|
transform.scale.z
|
|
@@ -5334,7 +5380,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5334
5380
|
writeEuler(transform.rotation, objectQuaternion);
|
|
5335
5381
|
}
|
|
5336
5382
|
held.tracker.record(
|
|
5337
|
-
held.remote ? new
|
|
5383
|
+
held.remote ? new THREE26.Vector3(
|
|
5338
5384
|
transform.position.x,
|
|
5339
5385
|
transform.position.y,
|
|
5340
5386
|
transform.position.z
|
|
@@ -5409,7 +5455,7 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5409
5455
|
*/
|
|
5410
5456
|
handPosition(input) {
|
|
5411
5457
|
if (input.gripPosition) return input.gripPosition;
|
|
5412
|
-
return new
|
|
5458
|
+
return new THREE26.Vector3().copy(input.rayDirection).multiplyScalar(RAYLESS_HOLD_DISTANCE).add(input.rayOrigin);
|
|
5413
5459
|
}
|
|
5414
5460
|
/**
|
|
5415
5461
|
* Hand orientation. Grip-less sources (gaze / transient-pointer) have none,
|
|
@@ -5417,8 +5463,8 @@ var _XRInteractionSystem = class _XRInteractionSystem {
|
|
|
5417
5463
|
*/
|
|
5418
5464
|
handQuaternion(input) {
|
|
5419
5465
|
if (input.gripQuaternion) return input.gripQuaternion.clone();
|
|
5420
|
-
return new
|
|
5421
|
-
new
|
|
5466
|
+
return new THREE26.Quaternion().setFromUnitVectors(
|
|
5467
|
+
new THREE26.Vector3(0, 0, -1),
|
|
5422
5468
|
input.rayDirection.clone().normalize()
|
|
5423
5469
|
);
|
|
5424
5470
|
}
|
|
@@ -5555,7 +5601,7 @@ function sampleTeleportArc(origin, direction, out = [], options) {
|
|
|
5555
5601
|
for (let i = 0; i < steps; i += 1) {
|
|
5556
5602
|
const t = i / (steps - 1) * maxTime;
|
|
5557
5603
|
out.push(
|
|
5558
|
-
new
|
|
5604
|
+
new THREE26.Vector3(
|
|
5559
5605
|
origin.x + velocity.x * t,
|
|
5560
5606
|
origin.y + velocity.y * t - 0.5 * gravity * t * t,
|
|
5561
5607
|
origin.z + velocity.z * t
|
|
@@ -5572,7 +5618,7 @@ function arcGroundCrossing(points, groundY) {
|
|
|
5572
5618
|
if (previous.y >= groundY && current.y <= groundY) {
|
|
5573
5619
|
const span = previous.y - current.y;
|
|
5574
5620
|
const alpha = span > 1e-6 ? (previous.y - groundY) / span : 0;
|
|
5575
|
-
return new
|
|
5621
|
+
return new THREE26.Vector3().lerpVectors(previous, current, alpha);
|
|
5576
5622
|
}
|
|
5577
5623
|
}
|
|
5578
5624
|
return null;
|
|
@@ -5616,11 +5662,11 @@ __name(_TeleportAimGate, "TeleportAimGate");
|
|
|
5616
5662
|
var TeleportAimGate = _TeleportAimGate;
|
|
5617
5663
|
|
|
5618
5664
|
// core/systems/XRLocomotionSystem.ts
|
|
5619
|
-
var UP = new
|
|
5665
|
+
var UP = new THREE26.Vector3(0, 1, 0);
|
|
5620
5666
|
var AXIS_DEADZONE = 0.5;
|
|
5621
5667
|
var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
5622
5668
|
constructor(inputSystem) {
|
|
5623
|
-
this.raycaster = new
|
|
5669
|
+
this.raycaster = new THREE26.Raycaster();
|
|
5624
5670
|
/** Per-source latch so one stick push yields exactly one snap turn. */
|
|
5625
5671
|
this.turnLatched = /* @__PURE__ */ new WeakSet();
|
|
5626
5672
|
/** Reused arc buffer — aiming runs every frame. */
|
|
@@ -5746,7 +5792,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
5746
5792
|
}
|
|
5747
5793
|
if (this.turnLatched.has(source)) continue;
|
|
5748
5794
|
this.turnLatched.add(source);
|
|
5749
|
-
transform.rotation.y -= Math.sign(x) *
|
|
5795
|
+
transform.rotation.y -= Math.sign(x) * THREE26.MathUtils.degToRad(rig.snapTurnDegrees);
|
|
5750
5796
|
}
|
|
5751
5797
|
}
|
|
5752
5798
|
applySmoothMove(world, rig, transform, inputs, deltaTime) {
|
|
@@ -5756,12 +5802,12 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
5756
5802
|
const y = input.axes[1] ?? 0;
|
|
5757
5803
|
if (Math.abs(x) < 0.15 && Math.abs(y) < 0.15) continue;
|
|
5758
5804
|
const camera = world.getCamera();
|
|
5759
|
-
const forward = new
|
|
5805
|
+
const forward = new THREE26.Vector3();
|
|
5760
5806
|
camera.getWorldDirection(forward);
|
|
5761
5807
|
forward.y = 0;
|
|
5762
5808
|
if (forward.lengthSq() < 1e-6) continue;
|
|
5763
5809
|
forward.normalize();
|
|
5764
|
-
const right = new
|
|
5810
|
+
const right = new THREE26.Vector3().crossVectors(forward, UP).normalize();
|
|
5765
5811
|
const step = rig.moveSpeed * Math.max(0, deltaTime);
|
|
5766
5812
|
transform.position.x += (forward.x * -y + right.x * x) * step;
|
|
5767
5813
|
transform.position.z += (forward.z * -y + right.z * x) * step;
|
|
@@ -5842,7 +5888,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
5842
5888
|
for (let i = 1; i < points.length; i += 1) {
|
|
5843
5889
|
const from = points[i - 1];
|
|
5844
5890
|
const to = points[i];
|
|
5845
|
-
const delta = new
|
|
5891
|
+
const delta = new THREE26.Vector3().subVectors(to, from);
|
|
5846
5892
|
const distance = delta.length();
|
|
5847
5893
|
if (distance < 1e-6) continue;
|
|
5848
5894
|
this.raycaster.set(from, delta.divideScalar(distance));
|
|
@@ -6115,12 +6161,12 @@ function planeColliderFromPolygon(polygon) {
|
|
|
6115
6161
|
}
|
|
6116
6162
|
__name(planeColliderFromPolygon, "planeColliderFromPolygon");
|
|
6117
6163
|
function writeXrMeshGeometry(vertices, indices, existing) {
|
|
6118
|
-
const geometry = existing ?? new
|
|
6164
|
+
const geometry = existing ?? new THREE26.BufferGeometry();
|
|
6119
6165
|
geometry.setAttribute(
|
|
6120
6166
|
"position",
|
|
6121
|
-
new
|
|
6167
|
+
new THREE26.BufferAttribute(vertices.slice(), 3)
|
|
6122
6168
|
);
|
|
6123
|
-
geometry.setIndex(new
|
|
6169
|
+
geometry.setIndex(new THREE26.BufferAttribute(indices.slice(), 1));
|
|
6124
6170
|
geometry.deleteAttribute("normal");
|
|
6125
6171
|
geometry.computeBoundingSphere();
|
|
6126
6172
|
geometry.computeVertexNormals();
|
|
@@ -6128,14 +6174,14 @@ function writeXrMeshGeometry(vertices, indices, existing) {
|
|
|
6128
6174
|
}
|
|
6129
6175
|
__name(writeXrMeshGeometry, "writeXrMeshGeometry");
|
|
6130
6176
|
function decomposeXrPose(matrixElements, target) {
|
|
6131
|
-
const matrix = new
|
|
6177
|
+
const matrix = new THREE26.Matrix4().fromArray(
|
|
6132
6178
|
matrixElements
|
|
6133
6179
|
);
|
|
6134
|
-
const position = new
|
|
6135
|
-
const quaternion = new
|
|
6136
|
-
const scale = new
|
|
6180
|
+
const position = new THREE26.Vector3();
|
|
6181
|
+
const quaternion = new THREE26.Quaternion();
|
|
6182
|
+
const scale = new THREE26.Vector3();
|
|
6137
6183
|
matrix.decompose(position, quaternion, scale);
|
|
6138
|
-
const euler = new
|
|
6184
|
+
const euler = new THREE26.Euler().setFromQuaternion(quaternion, "XYZ");
|
|
6139
6185
|
target.position.x = position.x;
|
|
6140
6186
|
target.position.y = position.y;
|
|
6141
6187
|
target.position.z = position.z;
|
|
@@ -6297,8 +6343,8 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
6297
6343
|
this.viewerPos = null;
|
|
6298
6344
|
/** The ONE global room mesh currently allowed to spawn. */
|
|
6299
6345
|
this.electedGlobalMesh = null;
|
|
6300
|
-
this.tmpViewerMatrix = new
|
|
6301
|
-
this.tmpViewPos = new
|
|
6346
|
+
this.tmpViewerMatrix = new THREE26.Matrix4();
|
|
6347
|
+
this.tmpViewPos = new THREE26.Vector3();
|
|
6302
6348
|
}
|
|
6303
6349
|
update(world, deltaTime = 0) {
|
|
6304
6350
|
const presenting = world.isXrPresenting();
|
|
@@ -6657,7 +6703,7 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
6657
6703
|
const geometry = writeXrMeshGeometry(mesh.vertices, mesh.indices);
|
|
6658
6704
|
const label = mesh.semanticLabel ?? null;
|
|
6659
6705
|
const isGlobalMesh = label === "global mesh";
|
|
6660
|
-
const material = new
|
|
6706
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
6661
6707
|
color: debugColorFor("mesh", label),
|
|
6662
6708
|
wireframe: true,
|
|
6663
6709
|
// The global scan is a coarse triangle soup of the whole room; at full
|
|
@@ -6678,8 +6724,8 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
6678
6724
|
depthTest: true,
|
|
6679
6725
|
depthWrite: false
|
|
6680
6726
|
});
|
|
6681
|
-
const root = new
|
|
6682
|
-
const child = new
|
|
6727
|
+
const root = new THREE26.Group();
|
|
6728
|
+
const child = new THREE26.Mesh(geometry, material);
|
|
6683
6729
|
child.visible = this.debugVisible;
|
|
6684
6730
|
child.renderOrder = DEBUG_RENDER_ORDER;
|
|
6685
6731
|
root.add(child);
|
|
@@ -6705,21 +6751,21 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
6705
6751
|
}
|
|
6706
6752
|
/** A thin box so a detected plane can be SEEN, not just collided with. */
|
|
6707
6753
|
attachPlaneDebug(world, entry, collider, semanticLabel) {
|
|
6708
|
-
const box = new
|
|
6754
|
+
const box = new THREE26.BoxGeometry(
|
|
6709
6755
|
collider.size.x,
|
|
6710
6756
|
collider.size.y,
|
|
6711
6757
|
collider.size.z
|
|
6712
6758
|
);
|
|
6713
|
-
const geometry = new
|
|
6759
|
+
const geometry = new THREE26.EdgesGeometry(box);
|
|
6714
6760
|
box.dispose();
|
|
6715
|
-
const material = new
|
|
6761
|
+
const material = new THREE26.LineBasicMaterial({
|
|
6716
6762
|
color: debugColorFor("plane", semanticLabel),
|
|
6717
6763
|
// Same depth policy as the mesh overlay — see createMeshEntity.
|
|
6718
6764
|
depthTest: true,
|
|
6719
6765
|
depthWrite: false
|
|
6720
6766
|
});
|
|
6721
|
-
const root = new
|
|
6722
|
-
const child = new
|
|
6767
|
+
const root = new THREE26.Group();
|
|
6768
|
+
const child = new THREE26.LineSegments(geometry, material);
|
|
6723
6769
|
child.renderOrder = DEBUG_RENDER_ORDER;
|
|
6724
6770
|
child.position.set(collider.offset.x, collider.offset.y, collider.offset.z);
|
|
6725
6771
|
child.visible = this.debugVisible;
|
|
@@ -6795,6 +6841,14 @@ function normalizeOrientation(value) {
|
|
|
6795
6841
|
return value === "horizontal" || value === "vertical" ? value : null;
|
|
6796
6842
|
}
|
|
6797
6843
|
__name(normalizeOrientation, "normalizeOrientation");
|
|
6844
|
+
var isDisplayOnlySlider = /* @__PURE__ */ __name((slider) => slider.readOnly === true || slider.variant !== void 0 && slider.variant !== "slider", "isDisplayOnlySlider");
|
|
6845
|
+
function snapToStep(value, slider) {
|
|
6846
|
+
const { step, min, max } = slider;
|
|
6847
|
+
if (!step || step <= 0) return value;
|
|
6848
|
+
const snapped = min + Math.round((value - min) / step) * step;
|
|
6849
|
+
return Math.min(max, Math.max(min, snapped));
|
|
6850
|
+
}
|
|
6851
|
+
__name(snapToStep, "snapToStep");
|
|
6798
6852
|
var MOUSE_CLICK_TRAVEL_PX = 6;
|
|
6799
6853
|
var PRESS_TINT_MIN_SECONDS = 0.1;
|
|
6800
6854
|
var PRESS_TINT = 0.72;
|
|
@@ -6808,11 +6862,12 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6808
6862
|
constructor(interaction, options) {
|
|
6809
6863
|
this.xrPresses = /* @__PURE__ */ new Map();
|
|
6810
6864
|
this.mousePress = null;
|
|
6811
|
-
|
|
6865
|
+
/** What each pointer is on. Two hands can rest on one widget. */
|
|
6866
|
+
this.hovers = /* @__PURE__ */ new Map();
|
|
6812
6867
|
/** entityId → seconds of pressed-tint left to display. */
|
|
6813
6868
|
this.tintFloors = /* @__PURE__ */ new Map();
|
|
6814
6869
|
this.tinted = /* @__PURE__ */ new Set();
|
|
6815
|
-
this.raycaster = new
|
|
6870
|
+
this.raycaster = new THREE26.Raycaster();
|
|
6816
6871
|
this.interaction = interaction;
|
|
6817
6872
|
this.inputSystem = options?.inputSystem ?? null;
|
|
6818
6873
|
interaction?.registerBusyContributor(
|
|
@@ -6822,8 +6877,10 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6822
6877
|
update(world, deltaTime = 0) {
|
|
6823
6878
|
if (world.isEditorMode()) return;
|
|
6824
6879
|
if (world.isXrPresenting()) {
|
|
6880
|
+
this.setHover(world, "mouse", null, null);
|
|
6825
6881
|
this.updateXr(world);
|
|
6826
6882
|
} else {
|
|
6883
|
+
this.dropGoneXrHovers(world, []);
|
|
6827
6884
|
this.updateMouse(world);
|
|
6828
6885
|
}
|
|
6829
6886
|
this.updateTints(world, deltaTime);
|
|
@@ -6837,6 +6894,7 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6837
6894
|
for (const input of inputs) {
|
|
6838
6895
|
const hover = interaction.getHoverForInput(input);
|
|
6839
6896
|
const hovered = hover ? this.widgetKind(world, hover.entityId) : null;
|
|
6897
|
+
this.setHover(world, input, hover && hovered ? hover.entityId : null, input);
|
|
6840
6898
|
if (input.selectStart && hover && hovered) {
|
|
6841
6899
|
this.xrPresses.set(input, {
|
|
6842
6900
|
entityId: hover.entityId,
|
|
@@ -6865,6 +6923,15 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6865
6923
|
for (const [input] of this.xrPresses) {
|
|
6866
6924
|
if (!inputs.includes(input)) this.xrPresses.delete(input);
|
|
6867
6925
|
}
|
|
6926
|
+
this.dropGoneXrHovers(world, inputs);
|
|
6927
|
+
}
|
|
6928
|
+
/** A transient source leaves with no select edge to clear its hover. */
|
|
6929
|
+
dropGoneXrHovers(world, inputs) {
|
|
6930
|
+
for (const source of [...this.hovers.keys()]) {
|
|
6931
|
+
if (source !== "mouse" && !inputs.includes(source)) {
|
|
6932
|
+
this.setHover(world, source, null, source);
|
|
6933
|
+
}
|
|
6934
|
+
}
|
|
6868
6935
|
}
|
|
6869
6936
|
// ── Mouse path (flat preview) ──────────────────────────────────────────────
|
|
6870
6937
|
updateMouse(world) {
|
|
@@ -6872,22 +6939,7 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6872
6939
|
if (!input) return;
|
|
6873
6940
|
const hit = this.raycastMouse(world);
|
|
6874
6941
|
const hovered = hit && this.widgetKind(world, hit) ? hit : null;
|
|
6875
|
-
|
|
6876
|
-
if (this.mouseHover !== null) {
|
|
6877
|
-
this.setTint(world, this.mouseHover, 1);
|
|
6878
|
-
this.dispatchBubbling(
|
|
6879
|
-
world,
|
|
6880
|
-
this.mouseHover,
|
|
6881
|
-
"onUiHoverEnd",
|
|
6882
|
-
(b, e) => b.onUiHoverEnd(e)
|
|
6883
|
-
);
|
|
6884
|
-
}
|
|
6885
|
-
if (hovered !== null) {
|
|
6886
|
-
this.setTint(world, hovered, HOVER_TINT);
|
|
6887
|
-
this.dispatchBubbling(world, hovered, "onUiHoverStart", (b, e) => b.onUiHoverStart(e));
|
|
6888
|
-
}
|
|
6889
|
-
this.mouseHover = hovered;
|
|
6890
|
-
}
|
|
6942
|
+
this.setHover(world, "mouse", hovered, null);
|
|
6891
6943
|
if (input.getMouseDown("left") && hovered) {
|
|
6892
6944
|
const kind = this.widgetKind(world, hovered);
|
|
6893
6945
|
if (kind) {
|
|
@@ -6895,12 +6947,12 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6895
6947
|
this.beginPressTint(world, hovered);
|
|
6896
6948
|
}
|
|
6897
6949
|
}
|
|
6898
|
-
if (this.mousePress) {
|
|
6950
|
+
if (this.mousePress && !input.getMouseDown("left")) {
|
|
6899
6951
|
const delta = input.getMouseDelta();
|
|
6900
6952
|
this.mousePress.travelPx += Math.hypot(delta.x, delta.y);
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6953
|
+
}
|
|
6954
|
+
if (this.mousePress?.kind === "slider") {
|
|
6955
|
+
this.dragSliderMouse(world, this.mousePress.entityId);
|
|
6904
6956
|
}
|
|
6905
6957
|
if (input.getMouseUp("left") && this.mousePress) {
|
|
6906
6958
|
const press = this.mousePress;
|
|
@@ -6929,15 +6981,24 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6929
6981
|
ndcY = -((pos.y - rect.top) / Math.max(1, rect.height) * 2 - 1);
|
|
6930
6982
|
if (ndcX < -1 || ndcX > 1 || ndcY < -1 || ndcY > 1) return null;
|
|
6931
6983
|
}
|
|
6932
|
-
this.raycaster.setFromCamera(new
|
|
6984
|
+
this.raycaster.setFromCamera(new THREE26.Vector2(ndcX, ndcY), world.getCamera());
|
|
6933
6985
|
const hits = world.raycast(
|
|
6934
6986
|
this.raycaster.ray.origin,
|
|
6935
6987
|
this.raycaster.ray.direction
|
|
6936
6988
|
);
|
|
6989
|
+
let surfaceTree = null;
|
|
6937
6990
|
for (const hit of hits) {
|
|
6938
|
-
|
|
6939
|
-
if (
|
|
6940
|
-
|
|
6991
|
+
const entityId = hit.entityId;
|
|
6992
|
+
if (typeof entityId !== "number") continue;
|
|
6993
|
+
if (!isShownInScene(world, entityId)) continue;
|
|
6994
|
+
if (this.widgetKind(world, entityId)) {
|
|
6995
|
+
const sameSurface = surfaceTree === null || widgetTreeRoot(world, entityId) === surfaceTree;
|
|
6996
|
+
return sameSurface ? entityId : null;
|
|
6997
|
+
}
|
|
6998
|
+
if (!isUiWidget(world, entityId)) return null;
|
|
6999
|
+
const tree = widgetTreeRoot(world, entityId);
|
|
7000
|
+
if (surfaceTree !== null && tree !== surfaceTree) return null;
|
|
7001
|
+
surfaceTree = tree;
|
|
6941
7002
|
}
|
|
6942
7003
|
return null;
|
|
6943
7004
|
}
|
|
@@ -6945,7 +7006,8 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6945
7006
|
widgetKind(world, entityId) {
|
|
6946
7007
|
if (world.getComponent(entityId, UIButtonComponent)) return "button";
|
|
6947
7008
|
if (world.getComponent(entityId, UIToggleComponent)) return "toggle";
|
|
6948
|
-
|
|
7009
|
+
const slider = world.getComponent(entityId, UISliderComponent);
|
|
7010
|
+
if (slider && !isDisplayOnlySlider(slider)) return "slider";
|
|
6949
7011
|
return null;
|
|
6950
7012
|
}
|
|
6951
7013
|
fire(world, press, input) {
|
|
@@ -6996,7 +7058,10 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
6996
7058
|
const inset = slider.height / 2;
|
|
6997
7059
|
const usable = Math.max(1e-3, slider.width - inset * 2);
|
|
6998
7060
|
const t = Math.min(1, Math.max(0, local.x / usable + 0.5));
|
|
6999
|
-
const next =
|
|
7061
|
+
const next = snapToStep(
|
|
7062
|
+
slider.min + t * (slider.max - slider.min),
|
|
7063
|
+
slider
|
|
7064
|
+
);
|
|
7000
7065
|
if (Math.abs(next - slider.value) < 1e-4) return;
|
|
7001
7066
|
slider.value = next;
|
|
7002
7067
|
this.dispatchBubbling(
|
|
@@ -7074,6 +7139,43 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
7074
7139
|
const name = world.getComponent(entityId, Name)?.value;
|
|
7075
7140
|
return typeof name === "string" ? name : String(entityId);
|
|
7076
7141
|
}
|
|
7142
|
+
// ── Hover ──────────────────────────────────────────────────────────────────
|
|
7143
|
+
setHover(world, source, next, input) {
|
|
7144
|
+
const previous = this.hovers.get(source) ?? null;
|
|
7145
|
+
if (previous === next) return;
|
|
7146
|
+
if (next === null) this.hovers.delete(source);
|
|
7147
|
+
else this.hovers.set(source, next);
|
|
7148
|
+
if (previous !== null && !this.isHovered(previous)) {
|
|
7149
|
+
if (!this.tintFloors.has(previous)) this.setTint(world, previous, 1);
|
|
7150
|
+
this.dispatchBubbling(
|
|
7151
|
+
world,
|
|
7152
|
+
previous,
|
|
7153
|
+
"onUiHoverEnd",
|
|
7154
|
+
(b, e) => b.onUiHoverEnd(e),
|
|
7155
|
+
input
|
|
7156
|
+
);
|
|
7157
|
+
}
|
|
7158
|
+
if (next !== null && this.hoverCount(next) === 1) {
|
|
7159
|
+
if (!this.tintFloors.has(next)) this.setTint(world, next, HOVER_TINT);
|
|
7160
|
+
this.dispatchBubbling(
|
|
7161
|
+
world,
|
|
7162
|
+
next,
|
|
7163
|
+
"onUiHoverStart",
|
|
7164
|
+
(b, e) => b.onUiHoverStart(e),
|
|
7165
|
+
input
|
|
7166
|
+
);
|
|
7167
|
+
}
|
|
7168
|
+
}
|
|
7169
|
+
hoverCount(entityId) {
|
|
7170
|
+
let count = 0;
|
|
7171
|
+
for (const hovered of this.hovers.values()) {
|
|
7172
|
+
if (hovered === entityId) count += 1;
|
|
7173
|
+
}
|
|
7174
|
+
return count;
|
|
7175
|
+
}
|
|
7176
|
+
isHovered(entityId) {
|
|
7177
|
+
return this.hoverCount(entityId) > 0;
|
|
7178
|
+
}
|
|
7077
7179
|
// ── Pressed/hover tint ─────────────────────────────────────────────────────
|
|
7078
7180
|
beginPressTint(world, entityId) {
|
|
7079
7181
|
this.setTint(world, entityId, PRESS_TINT);
|
|
@@ -7091,11 +7193,7 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
7091
7193
|
if (stillHeld) continue;
|
|
7092
7194
|
if (next <= 0) {
|
|
7093
7195
|
this.tintFloors.delete(entityId);
|
|
7094
|
-
this.setTint(
|
|
7095
|
-
world,
|
|
7096
|
-
entityId,
|
|
7097
|
-
this.mouseHover === entityId ? HOVER_TINT : 1
|
|
7098
|
-
);
|
|
7196
|
+
this.setTint(world, entityId, this.isHovered(entityId) ? HOVER_TINT : 1);
|
|
7099
7197
|
} else {
|
|
7100
7198
|
this.tintFloors.set(entityId, next);
|
|
7101
7199
|
}
|
|
@@ -7106,14 +7204,101 @@ var _UIInteractionSystem = class _UIInteractionSystem {
|
|
|
7106
7204
|
if (!object) return;
|
|
7107
7205
|
if (scalar === 1) this.tinted.delete(entityId);
|
|
7108
7206
|
else this.tinted.add(entityId);
|
|
7109
|
-
object.
|
|
7110
|
-
const
|
|
7111
|
-
if (
|
|
7112
|
-
|
|
7207
|
+
for (const child of object.children) {
|
|
7208
|
+
const tag = child.userData[UI_PART_KEY];
|
|
7209
|
+
if (!tag) continue;
|
|
7210
|
+
tag.tint = scalar;
|
|
7211
|
+
applyPartColor(child, tag);
|
|
7212
|
+
}
|
|
7113
7213
|
}
|
|
7114
7214
|
};
|
|
7115
7215
|
__name(_UIInteractionSystem, "UIInteractionSystem");
|
|
7116
7216
|
var UIInteractionSystem = _UIInteractionSystem;
|
|
7217
|
+
var fonts = /* @__PURE__ */ new Map();
|
|
7218
|
+
var images = /* @__PURE__ */ new Map();
|
|
7219
|
+
function hash(text) {
|
|
7220
|
+
let value = 5381;
|
|
7221
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
7222
|
+
value = (value * 33 ^ text.charCodeAt(i)) >>> 0;
|
|
7223
|
+
}
|
|
7224
|
+
return value.toString(36);
|
|
7225
|
+
}
|
|
7226
|
+
__name(hash, "hash");
|
|
7227
|
+
function tracked(url, work) {
|
|
7228
|
+
const manager = THREE26.DefaultLoadingManager;
|
|
7229
|
+
manager.itemStart(url);
|
|
7230
|
+
return work.catch((error) => {
|
|
7231
|
+
manager.itemError(url);
|
|
7232
|
+
throw error;
|
|
7233
|
+
}).finally(() => manager.itemEnd(url));
|
|
7234
|
+
}
|
|
7235
|
+
__name(tracked, "tracked");
|
|
7236
|
+
function uiFontFamily(src) {
|
|
7237
|
+
if (typeof FontFace === "undefined" || typeof document === "undefined") {
|
|
7238
|
+
return null;
|
|
7239
|
+
}
|
|
7240
|
+
const known = fonts.get(src);
|
|
7241
|
+
if (known) return known.value;
|
|
7242
|
+
const entry = { value: null, settled: false };
|
|
7243
|
+
fonts.set(src, entry);
|
|
7244
|
+
const url = resolvePrefabAssetUrl(src);
|
|
7245
|
+
const family = `relu-ui-${hash(url)}`;
|
|
7246
|
+
tracked(
|
|
7247
|
+
url,
|
|
7248
|
+
(async () => {
|
|
7249
|
+
const response = await fetch(url);
|
|
7250
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
7251
|
+
const buffer = await response.arrayBuffer();
|
|
7252
|
+
const face = new FontFace(family, buffer, { weight: "100 900" });
|
|
7253
|
+
await face.load();
|
|
7254
|
+
document.fonts.add(face);
|
|
7255
|
+
})()
|
|
7256
|
+
).then(() => {
|
|
7257
|
+
entry.value = family;
|
|
7258
|
+
}).catch((error) => {
|
|
7259
|
+
console.warn(`[spatial-ecs] Couldn't load UI font ${src}.`, error);
|
|
7260
|
+
}).finally(() => {
|
|
7261
|
+
entry.settled = true;
|
|
7262
|
+
});
|
|
7263
|
+
return null;
|
|
7264
|
+
}
|
|
7265
|
+
__name(uiFontFamily, "uiFontFamily");
|
|
7266
|
+
function uiImage(src) {
|
|
7267
|
+
if (typeof Image === "undefined" || typeof fetch === "undefined") {
|
|
7268
|
+
return null;
|
|
7269
|
+
}
|
|
7270
|
+
const known = images.get(src);
|
|
7271
|
+
if (known) return known.value;
|
|
7272
|
+
const entry = { value: null, settled: false };
|
|
7273
|
+
images.set(src, entry);
|
|
7274
|
+
const url = resolvePrefabAssetUrl(src);
|
|
7275
|
+
tracked(
|
|
7276
|
+
url,
|
|
7277
|
+
(async () => {
|
|
7278
|
+
const response = await fetch(url);
|
|
7279
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
7280
|
+
const blob = await response.blob();
|
|
7281
|
+
const typed = /\.svg(\?|#|$)/i.test(url) ? new Blob([blob], { type: "image/svg+xml" }) : blob;
|
|
7282
|
+
const image = new Image();
|
|
7283
|
+
const objectUrl = URL.createObjectURL(typed);
|
|
7284
|
+
try {
|
|
7285
|
+
image.src = objectUrl;
|
|
7286
|
+
await image.decode();
|
|
7287
|
+
return image;
|
|
7288
|
+
} finally {
|
|
7289
|
+
URL.revokeObjectURL(objectUrl);
|
|
7290
|
+
}
|
|
7291
|
+
})()
|
|
7292
|
+
).then((image) => {
|
|
7293
|
+
entry.value = image;
|
|
7294
|
+
}).catch((error) => {
|
|
7295
|
+
console.warn(`[spatial-ecs] Couldn't load UI image ${src}.`, error);
|
|
7296
|
+
}).finally(() => {
|
|
7297
|
+
entry.settled = true;
|
|
7298
|
+
});
|
|
7299
|
+
return null;
|
|
7300
|
+
}
|
|
7301
|
+
__name(uiImage, "uiImage");
|
|
7117
7302
|
|
|
7118
7303
|
// core/ui/uiCanvas.ts
|
|
7119
7304
|
var DEFAULT_PIXELS_PER_METER = 1024;
|
|
@@ -7186,18 +7371,21 @@ function clampLines(measure, lines, maxLines, maxWidthPx) {
|
|
|
7186
7371
|
}
|
|
7187
7372
|
__name(clampLines, "clampLines");
|
|
7188
7373
|
var UI_FONT_STACK = '-apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
7189
|
-
|
|
7190
|
-
|
|
7374
|
+
var NO_ASSETS = { image: /* @__PURE__ */ __name(() => null, "image") };
|
|
7375
|
+
function tracePath(ctx, x, y, w, h, radii) {
|
|
7376
|
+
const limit = Math.min(w / 2, h / 2);
|
|
7377
|
+
const fit = /* @__PURE__ */ __name((r) => Math.max(0, Math.min(r, limit)), "fit");
|
|
7378
|
+
const [tl, tr, br, bl] = (Array.isArray(radii) ? radii : [radii, radii, radii, radii]).map(fit);
|
|
7191
7379
|
ctx.beginPath();
|
|
7192
7380
|
if (typeof ctx.roundRect === "function") {
|
|
7193
|
-
ctx.roundRect(x, y, w, h,
|
|
7381
|
+
ctx.roundRect(x, y, w, h, [tl, tr, br, bl]);
|
|
7194
7382
|
return;
|
|
7195
7383
|
}
|
|
7196
|
-
ctx.moveTo(x +
|
|
7197
|
-
ctx.arcTo(x + w, y, x + w, y + h,
|
|
7198
|
-
ctx.arcTo(x + w, y + h, x, y + h,
|
|
7199
|
-
ctx.arcTo(x, y + h, x, y,
|
|
7200
|
-
ctx.arcTo(x, y, x + w, y,
|
|
7384
|
+
ctx.moveTo(x + tl, y);
|
|
7385
|
+
ctx.arcTo(x + w, y, x + w, y + h, tr);
|
|
7386
|
+
ctx.arcTo(x + w, y + h, x, y + h, br);
|
|
7387
|
+
ctx.arcTo(x, y + h, x, y, bl);
|
|
7388
|
+
ctx.arcTo(x, y, x + w, y, tl);
|
|
7201
7389
|
ctx.closePath();
|
|
7202
7390
|
}
|
|
7203
7391
|
__name(tracePath, "tracePath");
|
|
@@ -7217,108 +7405,244 @@ function withOpacity(ctx, color, opacity) {
|
|
|
7217
7405
|
return parsed;
|
|
7218
7406
|
}
|
|
7219
7407
|
__name(withOpacity, "withOpacity");
|
|
7220
|
-
function
|
|
7221
|
-
|
|
7222
|
-
const
|
|
7223
|
-
const
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7408
|
+
function fillStyleFor(ctx, paint, box, opacity) {
|
|
7409
|
+
if (paint.kind === "solid") return withOpacity(ctx, paint.color, opacity);
|
|
7410
|
+
const cx = box.x + box.w / 2;
|
|
7411
|
+
const cy = box.y + box.h / 2;
|
|
7412
|
+
let gradient;
|
|
7413
|
+
if (paint.kind === "linear") {
|
|
7414
|
+
const radians = paint.angle * Math.PI / 180;
|
|
7415
|
+
const dx = Math.sin(radians);
|
|
7416
|
+
const dy = -Math.cos(radians);
|
|
7417
|
+
const half = (Math.abs(box.w * dx) + Math.abs(box.h * dy)) / 2;
|
|
7418
|
+
gradient = ctx.createLinearGradient(
|
|
7419
|
+
cx - dx * half,
|
|
7420
|
+
cy - dy * half,
|
|
7421
|
+
cx + dx * half,
|
|
7422
|
+
cy + dy * half
|
|
7423
|
+
);
|
|
7424
|
+
} else {
|
|
7425
|
+
gradient = ctx.createRadialGradient(
|
|
7426
|
+
cx,
|
|
7427
|
+
cy,
|
|
7428
|
+
0,
|
|
7429
|
+
cx,
|
|
7430
|
+
cy,
|
|
7431
|
+
Math.max(box.w, box.h) / 2
|
|
7432
|
+
);
|
|
7433
|
+
}
|
|
7434
|
+
for (const stop of paint.stops) {
|
|
7435
|
+
gradient.addColorStop(stop.at, withOpacity(ctx, stop.color, opacity));
|
|
7436
|
+
}
|
|
7437
|
+
return gradient;
|
|
7438
|
+
}
|
|
7439
|
+
__name(fillStyleFor, "fillStyleFor");
|
|
7440
|
+
function drawImagePaint(ctx, paint, box, assets) {
|
|
7441
|
+
const image = assets.image(paint.src);
|
|
7442
|
+
if (!image) return;
|
|
7443
|
+
const sourceW = image.naturalWidth || box.w;
|
|
7444
|
+
const sourceH = image.naturalHeight || box.h;
|
|
7445
|
+
const scale = paint.fit === "fill" ? 1 : paint.fit === "cover" ? Math.max(box.w / sourceW, box.h / sourceH) : Math.min(box.w / sourceW, box.h / sourceH);
|
|
7446
|
+
const w = paint.fit === "fill" ? box.w : sourceW * scale;
|
|
7447
|
+
const h = paint.fit === "fill" ? box.h : sourceH * scale;
|
|
7448
|
+
const x = box.x + (box.w - w) / 2;
|
|
7449
|
+
const y = box.y + (box.h - h) / 2;
|
|
7450
|
+
if (!paint.tint) {
|
|
7451
|
+
ctx.drawImage(image, x, y, w, h);
|
|
7452
|
+
return;
|
|
7453
|
+
}
|
|
7454
|
+
const scratch = assets.scratch?.(Math.ceil(w), Math.ceil(h));
|
|
7455
|
+
if (!scratch) {
|
|
7456
|
+
ctx.drawImage(image, x, y, w, h);
|
|
7457
|
+
return;
|
|
7458
|
+
}
|
|
7459
|
+
scratch.drawImage(image, 0, 0, w, h);
|
|
7460
|
+
scratch.globalCompositeOperation = "source-in";
|
|
7461
|
+
scratch.fillStyle = paint.tint;
|
|
7462
|
+
scratch.fillRect(0, 0, w, h);
|
|
7463
|
+
ctx.drawImage(scratch.canvas, x, y, w, h);
|
|
7464
|
+
}
|
|
7465
|
+
__name(drawImagePaint, "drawImagePaint");
|
|
7466
|
+
function pxRadii(radius, density) {
|
|
7467
|
+
return radius.map((r) => r * density);
|
|
7468
|
+
}
|
|
7469
|
+
__name(pxRadii, "pxRadii");
|
|
7470
|
+
function drawBoxShadow(ctx, box, radii, shadow, density) {
|
|
7471
|
+
ctx.save();
|
|
7472
|
+
ctx.shadowColor = shadow.color;
|
|
7473
|
+
ctx.shadowBlur = shadow.blur * density;
|
|
7474
|
+
ctx.shadowOffsetX = shadow.x * density;
|
|
7475
|
+
ctx.shadowOffsetY = -shadow.y * density;
|
|
7476
|
+
ctx.fillStyle = "#000000";
|
|
7477
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7230
7478
|
ctx.fill();
|
|
7231
|
-
|
|
7479
|
+
ctx.restore();
|
|
7480
|
+
ctx.save();
|
|
7481
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
7482
|
+
ctx.fillStyle = "#000000";
|
|
7483
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7484
|
+
ctx.fill();
|
|
7485
|
+
ctx.restore();
|
|
7486
|
+
}
|
|
7487
|
+
__name(drawBoxShadow, "drawBoxShadow");
|
|
7488
|
+
function drawChrome(ctx, box, density, chrome, assets = NO_ASSETS) {
|
|
7489
|
+
const radii = pxRadii(chrome.radius, density);
|
|
7490
|
+
for (const shadow of chrome.shadows) {
|
|
7491
|
+
drawBoxShadow(ctx, box, radii, shadow, density);
|
|
7492
|
+
}
|
|
7493
|
+
const opacity = Math.max(0, Math.min(1, chrome.fillOpacity));
|
|
7494
|
+
if (chrome.fill?.kind === "image") {
|
|
7495
|
+
ctx.save();
|
|
7496
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7497
|
+
ctx.clip();
|
|
7498
|
+
ctx.globalAlpha = opacity;
|
|
7499
|
+
drawImagePaint(ctx, chrome.fill, box, assets);
|
|
7500
|
+
ctx.restore();
|
|
7501
|
+
} else if (chrome.fill) {
|
|
7502
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7503
|
+
ctx.fillStyle = fillStyleFor(ctx, chrome.fill, box, opacity);
|
|
7504
|
+
ctx.fill();
|
|
7505
|
+
}
|
|
7506
|
+
if (chrome.edge) {
|
|
7507
|
+
const width = chrome.edge.width * density;
|
|
7508
|
+
ctx.save();
|
|
7509
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7510
|
+
ctx.clip();
|
|
7511
|
+
const fade = ctx.createLinearGradient(0, box.y, 0, box.y + box.h / 2);
|
|
7512
|
+
fade.addColorStop(0, chrome.edge.color);
|
|
7513
|
+
fade.addColorStop(1, withOpacity(ctx, chrome.edge.color, 0));
|
|
7514
|
+
ctx.strokeStyle = fade;
|
|
7515
|
+
ctx.lineWidth = width * 2;
|
|
7516
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7517
|
+
ctx.stroke();
|
|
7518
|
+
ctx.restore();
|
|
7519
|
+
}
|
|
7520
|
+
if (chrome.border) {
|
|
7521
|
+
const border = chrome.border.width * density;
|
|
7232
7522
|
tracePath(
|
|
7233
7523
|
ctx,
|
|
7234
|
-
border / 2,
|
|
7235
|
-
border / 2,
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
Math.max(0,
|
|
7524
|
+
box.x + border / 2,
|
|
7525
|
+
box.y + border / 2,
|
|
7526
|
+
box.w - border,
|
|
7527
|
+
box.h - border,
|
|
7528
|
+
radii.map((r) => Math.max(0, r - border / 2))
|
|
7239
7529
|
);
|
|
7240
|
-
ctx.strokeStyle =
|
|
7530
|
+
ctx.strokeStyle = chrome.border.color;
|
|
7241
7531
|
ctx.lineWidth = border;
|
|
7242
7532
|
ctx.stroke();
|
|
7243
7533
|
}
|
|
7244
7534
|
}
|
|
7245
7535
|
__name(drawChrome, "drawChrome");
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
const
|
|
7250
|
-
|
|
7536
|
+
var applyTransform2 = /* @__PURE__ */ __name((text, transform) => transform === "upper" ? text.toUpperCase() : transform === "lower" ? text.toLowerCase() : text, "applyTransform");
|
|
7537
|
+
function fillTracked(ctx, line, x, y, trackingPx, width) {
|
|
7538
|
+
let cursor = ctx.textAlign === "center" ? x - width / 2 : ctx.textAlign === "right" ? x - width : x;
|
|
7539
|
+
const align = ctx.textAlign;
|
|
7540
|
+
ctx.textAlign = "left";
|
|
7541
|
+
for (const glyph of line) {
|
|
7542
|
+
ctx.fillText(glyph, cursor, y);
|
|
7543
|
+
cursor += ctx.measureText(glyph).width + trackingPx;
|
|
7544
|
+
}
|
|
7545
|
+
ctx.textAlign = align;
|
|
7546
|
+
}
|
|
7547
|
+
__name(fillTracked, "fillTracked");
|
|
7548
|
+
function drawTextBlock(ctx, box, density, text, style, family = null, assets = NO_ASSETS) {
|
|
7549
|
+
const fontPx = Math.max(4, style.fontSize * density);
|
|
7550
|
+
const paddingPx = style.padding * density;
|
|
7551
|
+
const contentW = Math.max(1, box.w - paddingPx * 2);
|
|
7552
|
+
const contentH = Math.max(1, box.h - paddingPx * 2);
|
|
7251
7553
|
const lineHeightPx = fontPx * style.lineHeight;
|
|
7252
|
-
|
|
7253
|
-
const
|
|
7254
|
-
|
|
7554
|
+
const trackingPx = style.tracking * density;
|
|
7555
|
+
const stack = family ? `"${family}", ${UI_FONT_STACK}` : UI_FONT_STACK;
|
|
7556
|
+
ctx.font = `${style.fontWeight} ${fontPx}px ${stack}`;
|
|
7557
|
+
const nativeTracking = trackingPx !== 0 && "letterSpacing" in ctx;
|
|
7558
|
+
if (nativeTracking) {
|
|
7559
|
+
ctx.letterSpacing = `${trackingPx}px`;
|
|
7560
|
+
}
|
|
7561
|
+
const manualTracking = trackingPx !== 0 && !nativeTracking;
|
|
7562
|
+
const measure = /* @__PURE__ */ __name((s) => ctx.measureText(s).width + (manualTracking ? trackingPx * s.length : 0), "measure");
|
|
7563
|
+
const fits = Math.max(1, Math.floor(contentH / lineHeightPx));
|
|
7564
|
+
const maxLines = style.maxLines ? Math.min(fits, style.maxLines) : fits;
|
|
7255
7565
|
const lines = clampLines(
|
|
7256
7566
|
measure,
|
|
7257
|
-
wrapText(measure, text, contentW),
|
|
7567
|
+
wrapText(measure, applyTransform2(text, style.transform), contentW),
|
|
7258
7568
|
maxLines,
|
|
7259
7569
|
contentW
|
|
7260
7570
|
);
|
|
7261
7571
|
const blockH = lines.length * lineHeightPx;
|
|
7262
|
-
const top = style.valign === "top" ? paddingPx : style.valign === "bottom" ?
|
|
7263
|
-
const anchorX = style.align === "left" ? paddingPx : style.align === "right" ?
|
|
7572
|
+
const top = style.valign === "top" ? box.y + paddingPx : style.valign === "bottom" ? box.y + box.h - paddingPx - blockH : box.y + (box.h - blockH) / 2;
|
|
7573
|
+
const anchorX = style.align === "left" ? box.x + paddingPx : style.align === "right" ? box.x + box.w - paddingPx : box.x + box.w / 2;
|
|
7264
7574
|
ctx.save();
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7575
|
+
if (style.paint.kind === "image") {
|
|
7576
|
+
ctx.fillStyle = "#ffffff";
|
|
7577
|
+
} else {
|
|
7578
|
+
ctx.fillStyle = fillStyleFor(ctx, style.paint, box, 1);
|
|
7579
|
+
}
|
|
7580
|
+
if (style.shadow) {
|
|
7581
|
+
ctx.shadowColor = style.shadow.color;
|
|
7582
|
+
ctx.shadowBlur = style.shadow.blur * density;
|
|
7583
|
+
ctx.shadowOffsetX = style.shadow.x * density;
|
|
7584
|
+
ctx.shadowOffsetY = -style.shadow.y * density;
|
|
7585
|
+
}
|
|
7268
7586
|
ctx.textAlign = style.align;
|
|
7269
7587
|
ctx.textBaseline = "middle";
|
|
7270
7588
|
for (let i = 0; i < lines.length; i += 1) {
|
|
7271
|
-
|
|
7589
|
+
const y = top + (i + 0.5) * lineHeightPx;
|
|
7590
|
+
if (manualTracking) {
|
|
7591
|
+
fillTracked(ctx, lines[i], anchorX, y, trackingPx, measure(lines[i]));
|
|
7592
|
+
} else {
|
|
7593
|
+
ctx.fillText(lines[i], anchorX, y);
|
|
7594
|
+
}
|
|
7272
7595
|
}
|
|
7273
7596
|
ctx.restore();
|
|
7597
|
+
if (style.paint.kind === "image") {
|
|
7598
|
+
ctx.save();
|
|
7599
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
7600
|
+
drawImagePaint(ctx, style.paint, box, assets);
|
|
7601
|
+
ctx.restore();
|
|
7602
|
+
}
|
|
7603
|
+
if (nativeTracking) {
|
|
7604
|
+
ctx.letterSpacing = "0px";
|
|
7605
|
+
}
|
|
7274
7606
|
}
|
|
7275
7607
|
__name(drawTextBlock, "drawTextBlock");
|
|
7276
|
-
function panelSignature(widthM, heightM, size,
|
|
7608
|
+
function panelSignature(widthM, heightM, size, chrome, loaded = null) {
|
|
7277
7609
|
return JSON.stringify([
|
|
7278
7610
|
widthM,
|
|
7279
7611
|
heightM,
|
|
7280
7612
|
size.pxWidth,
|
|
7281
7613
|
size.pxHeight,
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
style.cornerRadiusMeters,
|
|
7285
|
-
style.borderWidthMeters,
|
|
7286
|
-
style.borderColor
|
|
7614
|
+
chrome,
|
|
7615
|
+
loaded
|
|
7287
7616
|
]);
|
|
7288
7617
|
}
|
|
7289
7618
|
__name(panelSignature, "panelSignature");
|
|
7290
|
-
function textSignature(widthM, heightM, size, text, style) {
|
|
7619
|
+
function textSignature(widthM, heightM, size, text, style, family = null) {
|
|
7291
7620
|
return JSON.stringify([
|
|
7292
7621
|
widthM,
|
|
7293
7622
|
heightM,
|
|
7294
7623
|
size.pxWidth,
|
|
7295
7624
|
size.pxHeight,
|
|
7296
7625
|
text,
|
|
7297
|
-
style
|
|
7298
|
-
|
|
7299
|
-
style.color,
|
|
7300
|
-
style.align,
|
|
7301
|
-
style.valign,
|
|
7302
|
-
style.lineHeight,
|
|
7303
|
-
style.paddingMeters
|
|
7626
|
+
style,
|
|
7627
|
+
family
|
|
7304
7628
|
]);
|
|
7305
7629
|
}
|
|
7306
7630
|
__name(textSignature, "textSignature");
|
|
7307
|
-
function buttonSignature(widthM, heightM, size,
|
|
7631
|
+
function buttonSignature(widthM, heightM, size, chrome, label, text, family = null, loaded = null) {
|
|
7308
7632
|
return JSON.stringify([
|
|
7309
|
-
panelSignature(widthM, heightM, size,
|
|
7633
|
+
panelSignature(widthM, heightM, size, chrome, loaded),
|
|
7310
7634
|
label,
|
|
7311
|
-
text
|
|
7312
|
-
|
|
7313
|
-
text.color
|
|
7635
|
+
text,
|
|
7636
|
+
family
|
|
7314
7637
|
]);
|
|
7315
7638
|
}
|
|
7316
7639
|
__name(buttonSignature, "buttonSignature");
|
|
7317
|
-
function trackSignature(widthM, heightM, size,
|
|
7640
|
+
function trackSignature(widthM, heightM, size, chrome, accentColor, knobColor, variant = null) {
|
|
7318
7641
|
return JSON.stringify([
|
|
7319
|
-
panelSignature(widthM, heightM, size,
|
|
7642
|
+
panelSignature(widthM, heightM, size, chrome),
|
|
7320
7643
|
accentColor,
|
|
7321
|
-
knobColor
|
|
7644
|
+
knobColor,
|
|
7645
|
+
variant
|
|
7322
7646
|
]);
|
|
7323
7647
|
}
|
|
7324
7648
|
__name(trackSignature, "trackSignature");
|
|
@@ -7328,17 +7652,226 @@ function drawRoundedBar(ctx, pxX, pxY, pxW, pxH, color) {
|
|
|
7328
7652
|
ctx.fill();
|
|
7329
7653
|
}
|
|
7330
7654
|
__name(drawRoundedBar, "drawRoundedBar");
|
|
7655
|
+
function drawCheckMark(ctx, box, color) {
|
|
7656
|
+
ctx.beginPath();
|
|
7657
|
+
ctx.moveTo(box.x + box.w * 0.24, box.y + box.h * 0.54);
|
|
7658
|
+
ctx.lineTo(box.x + box.w * 0.43, box.y + box.h * 0.72);
|
|
7659
|
+
ctx.lineTo(box.x + box.w * 0.77, box.y + box.h * 0.3);
|
|
7660
|
+
ctx.strokeStyle = color;
|
|
7661
|
+
ctx.lineWidth = box.h * 0.13;
|
|
7662
|
+
ctx.lineCap = "round";
|
|
7663
|
+
ctx.lineJoin = "round";
|
|
7664
|
+
ctx.stroke();
|
|
7665
|
+
}
|
|
7666
|
+
__name(drawCheckMark, "drawCheckMark");
|
|
7667
|
+
function drawDot(ctx, cx, cy, radius, color) {
|
|
7668
|
+
ctx.beginPath();
|
|
7669
|
+
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
|
|
7670
|
+
ctx.fillStyle = color;
|
|
7671
|
+
ctx.fill();
|
|
7672
|
+
}
|
|
7673
|
+
__name(drawDot, "drawDot");
|
|
7674
|
+
function drawRing(ctx, box, t, trackColor, accentColor) {
|
|
7675
|
+
const thickness = Math.min(box.w, box.h) * 0.14;
|
|
7676
|
+
const radius = Math.min(box.w, box.h) / 2 - thickness / 2;
|
|
7677
|
+
const cx = box.x + box.w / 2;
|
|
7678
|
+
const cy = box.y + box.h / 2;
|
|
7679
|
+
ctx.lineWidth = thickness;
|
|
7680
|
+
ctx.lineCap = "round";
|
|
7681
|
+
ctx.beginPath();
|
|
7682
|
+
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
|
|
7683
|
+
ctx.strokeStyle = trackColor;
|
|
7684
|
+
ctx.stroke();
|
|
7685
|
+
if (t <= 0) return;
|
|
7686
|
+
const start = -Math.PI / 2;
|
|
7687
|
+
ctx.beginPath();
|
|
7688
|
+
ctx.arc(cx, cy, radius, start, start + t * Math.PI * 2);
|
|
7689
|
+
ctx.strokeStyle = accentColor;
|
|
7690
|
+
ctx.stroke();
|
|
7691
|
+
}
|
|
7692
|
+
__name(drawRing, "drawRing");
|
|
7693
|
+
function drawIconLabel(ctx, box, density, label, style, family, icon, position, assets) {
|
|
7694
|
+
const fontPx = style.fontSize * density;
|
|
7695
|
+
const iconPx = fontPx * 1.3;
|
|
7696
|
+
const gapPx = label ? fontPx * 0.5 : 0;
|
|
7697
|
+
const stack = family ? `"${family}", ${UI_FONT_STACK}` : UI_FONT_STACK;
|
|
7698
|
+
ctx.font = `${style.fontWeight} ${fontPx}px ${stack}`;
|
|
7699
|
+
const labelPx = label ? ctx.measureText(label).width : 0;
|
|
7700
|
+
const groupPx = iconPx + gapPx + labelPx;
|
|
7701
|
+
const startX = box.x + (box.w - groupPx) / 2;
|
|
7702
|
+
const iconX = position === "left" ? startX : startX + labelPx + gapPx;
|
|
7703
|
+
const labelX = position === "left" ? startX + iconPx + gapPx : startX;
|
|
7704
|
+
drawImagePaint(
|
|
7705
|
+
ctx,
|
|
7706
|
+
{ src: icon, fit: "contain", tint: style.color },
|
|
7707
|
+
{ x: iconX, y: box.y + (box.h - iconPx) / 2, w: iconPx, h: iconPx },
|
|
7708
|
+
assets
|
|
7709
|
+
);
|
|
7710
|
+
if (label) {
|
|
7711
|
+
drawTextBlock(
|
|
7712
|
+
ctx,
|
|
7713
|
+
{ x: labelX, y: box.y, w: labelPx + 2, h: box.h },
|
|
7714
|
+
density,
|
|
7715
|
+
label,
|
|
7716
|
+
{ ...style, align: "left", padding: 0 },
|
|
7717
|
+
family,
|
|
7718
|
+
assets
|
|
7719
|
+
);
|
|
7720
|
+
}
|
|
7721
|
+
}
|
|
7722
|
+
__name(drawIconLabel, "drawIconLabel");
|
|
7723
|
+
|
|
7724
|
+
// core/ui/uiPaintOrder.ts
|
|
7725
|
+
var BASE_RENDER_ORDER = 10;
|
|
7726
|
+
var MAX_RENDER_ORDER = 890;
|
|
7727
|
+
var MAX_TREE_RANK = MAX_RENDER_ORDER - BASE_RENDER_ORDER - 1;
|
|
7728
|
+
var SLOT_STEP = 1e-4;
|
|
7729
|
+
var SLOTS_PER_WIDGET = 3;
|
|
7730
|
+
var MAX_WIDGET_INDEX = Math.floor(1 / SLOT_STEP / SLOTS_PER_WIDGET) - 1;
|
|
7731
|
+
var PLANE_EPSILON_METERS = 1e-3;
|
|
7732
|
+
var PARALLEL_DOT = 1 - 1e-4;
|
|
7733
|
+
var dot = /* @__PURE__ */ __name((a, b) => a.x * b.x + a.y * b.y + a.z * b.z, "dot");
|
|
7734
|
+
var length = /* @__PURE__ */ __name((a) => Math.sqrt(dot(a, a)), "length");
|
|
7735
|
+
var subtract = /* @__PURE__ */ __name((a, b) => ({
|
|
7736
|
+
x: a.x - b.x,
|
|
7737
|
+
y: a.y - b.y,
|
|
7738
|
+
z: a.z - b.z
|
|
7739
|
+
}), "subtract");
|
|
7740
|
+
function unit(a) {
|
|
7741
|
+
const len = length(a);
|
|
7742
|
+
if (len < 1e-9) return { x: 0, y: 0, z: 0 };
|
|
7743
|
+
return { x: a.x / len, y: a.y / len, z: a.z / len };
|
|
7744
|
+
}
|
|
7745
|
+
__name(unit, "unit");
|
|
7746
|
+
function normalOf(rect) {
|
|
7747
|
+
const { halfX: a, halfY: b } = rect;
|
|
7748
|
+
return unit({
|
|
7749
|
+
x: a.y * b.z - a.z * b.y,
|
|
7750
|
+
y: a.z * b.x - a.x * b.z,
|
|
7751
|
+
z: a.x * b.y - a.y * b.x
|
|
7752
|
+
});
|
|
7753
|
+
}
|
|
7754
|
+
__name(normalOf, "normalOf");
|
|
7755
|
+
var planeDistance = /* @__PURE__ */ __name((rect, normal, eye) => Math.abs(dot(subtract(eye, rect.center), normal)), "planeDistance");
|
|
7756
|
+
function closestPointDistance(rect, eye) {
|
|
7757
|
+
const toEye = subtract(eye, rect.center);
|
|
7758
|
+
const lenX = length(rect.halfX);
|
|
7759
|
+
const lenY = length(rect.halfY);
|
|
7760
|
+
const axisX = unit(rect.halfX);
|
|
7761
|
+
const axisY = unit(rect.halfY);
|
|
7762
|
+
const s = Math.max(-lenX, Math.min(lenX, dot(toEye, axisX)));
|
|
7763
|
+
const t = Math.max(-lenY, Math.min(lenY, dot(toEye, axisY)));
|
|
7764
|
+
return length({
|
|
7765
|
+
x: toEye.x - axisX.x * s - axisY.x * t,
|
|
7766
|
+
y: toEye.y - axisX.y * s - axisY.y * t,
|
|
7767
|
+
z: toEye.z - axisX.z * s - axisY.z * t
|
|
7768
|
+
});
|
|
7769
|
+
}
|
|
7770
|
+
__name(closestPointDistance, "closestPointDistance");
|
|
7771
|
+
var areaOf = /* @__PURE__ */ __name((rect) => length(rect.halfX) * length(rect.halfY), "areaOf");
|
|
7772
|
+
function comparePaintRects(a, b, eye) {
|
|
7773
|
+
const normalA = normalOf(a);
|
|
7774
|
+
const normalB = normalOf(b);
|
|
7775
|
+
const parallel = Math.abs(dot(normalA, normalB)) >= PARALLEL_DOT;
|
|
7776
|
+
const distanceA = parallel ? planeDistance(a, normalA, eye) : closestPointDistance(a, eye);
|
|
7777
|
+
const distanceB = parallel ? planeDistance(b, normalB, eye) : closestPointDistance(b, eye);
|
|
7778
|
+
if (Math.abs(distanceA - distanceB) > PLANE_EPSILON_METERS) {
|
|
7779
|
+
return distanceB - distanceA;
|
|
7780
|
+
}
|
|
7781
|
+
const areaA = areaOf(a);
|
|
7782
|
+
const areaB = areaOf(b);
|
|
7783
|
+
if (areaA !== areaB) return areaB - areaA;
|
|
7784
|
+
return a.id - b.id;
|
|
7785
|
+
}
|
|
7786
|
+
__name(comparePaintRects, "comparePaintRects");
|
|
7787
|
+
function buildPaintTrees(nodes) {
|
|
7788
|
+
const known = new Set(nodes.map((node) => node.id));
|
|
7789
|
+
const children = /* @__PURE__ */ new Map();
|
|
7790
|
+
const roots = [];
|
|
7791
|
+
for (const node of nodes) {
|
|
7792
|
+
if (node.parent !== null && known.has(node.parent)) {
|
|
7793
|
+
const siblings = children.get(node.parent);
|
|
7794
|
+
if (siblings) siblings.push(node.id);
|
|
7795
|
+
else children.set(node.parent, [node.id]);
|
|
7796
|
+
} else {
|
|
7797
|
+
roots.push(node.id);
|
|
7798
|
+
}
|
|
7799
|
+
}
|
|
7800
|
+
const trees = [];
|
|
7801
|
+
const visited = /* @__PURE__ */ new Set();
|
|
7802
|
+
const walk = /* @__PURE__ */ __name((id, order) => {
|
|
7803
|
+
if (visited.has(id)) return;
|
|
7804
|
+
visited.add(id);
|
|
7805
|
+
order.push(id);
|
|
7806
|
+
const kids = children.get(id);
|
|
7807
|
+
if (!kids) return;
|
|
7808
|
+
for (const kid of [...kids].sort((a, b) => a - b)) walk(kid, order);
|
|
7809
|
+
}, "walk");
|
|
7810
|
+
for (const rootId of [...roots].sort((a, b) => a - b)) {
|
|
7811
|
+
const order = [];
|
|
7812
|
+
walk(rootId, order);
|
|
7813
|
+
trees.push({ rootId, order });
|
|
7814
|
+
}
|
|
7815
|
+
return trees;
|
|
7816
|
+
}
|
|
7817
|
+
__name(buildPaintTrees, "buildPaintTrees");
|
|
7818
|
+
function paintSlots(treeRank, widgetIndex) {
|
|
7819
|
+
const base = BASE_RENDER_ORDER + Math.min(treeRank, MAX_TREE_RANK);
|
|
7820
|
+
const index = Math.min(widgetIndex, MAX_WIDGET_INDEX);
|
|
7821
|
+
const slot = /* @__PURE__ */ __name((offset) => base + (index * SLOTS_PER_WIDGET + offset) * SLOT_STEP, "slot");
|
|
7822
|
+
return { face: slot(0), parts: slot(1), descendants: slot(2) };
|
|
7823
|
+
}
|
|
7824
|
+
__name(paintSlots, "paintSlots");
|
|
7825
|
+
function assignPaintOrder(trees, rects, eye) {
|
|
7826
|
+
const sorted = trees.filter((tree) => rects.has(tree.rootId)).sort(
|
|
7827
|
+
(a, b) => comparePaintRects(
|
|
7828
|
+
rects.get(a.rootId),
|
|
7829
|
+
rects.get(b.rootId),
|
|
7830
|
+
eye
|
|
7831
|
+
)
|
|
7832
|
+
);
|
|
7833
|
+
const slots = /* @__PURE__ */ new Map();
|
|
7834
|
+
sorted.forEach((tree, rank) => {
|
|
7835
|
+
tree.order.forEach((id, index) => {
|
|
7836
|
+
slots.set(id, paintSlots(rank, index));
|
|
7837
|
+
});
|
|
7838
|
+
});
|
|
7839
|
+
return slots;
|
|
7840
|
+
}
|
|
7841
|
+
__name(assignPaintOrder, "assignPaintOrder");
|
|
7331
7842
|
|
|
7332
7843
|
// core/systems/UIPanelSystem.ts
|
|
7333
|
-
var FACE_RENDER_ORDER = 10;
|
|
7334
7844
|
var CHILD_Z = 2e-3;
|
|
7845
|
+
var DESCENDANT_WALK_INTERVAL = 30;
|
|
7846
|
+
var METER_STEPS = 200;
|
|
7847
|
+
var CLEAR_CHROME = {
|
|
7848
|
+
backgroundColor: "#000000",
|
|
7849
|
+
backgroundOpacity: 0,
|
|
7850
|
+
cornerRadius: 0,
|
|
7851
|
+
borderWidth: 0,
|
|
7852
|
+
borderColor: "#000000"
|
|
7853
|
+
};
|
|
7854
|
+
var PAINT_STAMP_KEY = "__uiPaintStamp";
|
|
7335
7855
|
var _UIPanelSystem = class _UIPanelSystem {
|
|
7336
7856
|
constructor(options) {
|
|
7337
7857
|
this.entries = /* @__PURE__ */ new Map();
|
|
7858
|
+
this.framesUntilDescendantWalk = 0;
|
|
7859
|
+
/** Whether any panel defines tokens, so plain scenes skip the parent walk. */
|
|
7860
|
+
this.anyTokens = false;
|
|
7861
|
+
this.drawAssets = {
|
|
7862
|
+
image: /* @__PURE__ */ __name((src) => uiImage(src), "image"),
|
|
7863
|
+
scratch: /* @__PURE__ */ __name((width, height) => {
|
|
7864
|
+
const canvas = this.createCanvas();
|
|
7865
|
+
canvas.width = width;
|
|
7866
|
+
canvas.height = height;
|
|
7867
|
+
return canvas.getContext("2d");
|
|
7868
|
+
}, "scratch")
|
|
7869
|
+
};
|
|
7338
7870
|
this.createCanvas = options?.createCanvas ?? (() => document.createElement("canvas"));
|
|
7339
7871
|
}
|
|
7340
7872
|
update(world, deltaTime = 0) {
|
|
7341
7873
|
const live = /* @__PURE__ */ new Set();
|
|
7874
|
+
this.anyTokens = world.query(UIPanelComponent).some((id) => world.getComponent(id, UIPanelComponent)?.tokens);
|
|
7342
7875
|
for (const entityId of world.query(UIPanelComponent, Object3DRef)) {
|
|
7343
7876
|
const panel = world.getComponent(entityId, UIPanelComponent);
|
|
7344
7877
|
if (!panel) continue;
|
|
@@ -7376,6 +7909,7 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7376
7909
|
this.entries.delete(entityId);
|
|
7377
7910
|
}
|
|
7378
7911
|
}
|
|
7912
|
+
this.applyPaintOrder(world);
|
|
7379
7913
|
}
|
|
7380
7914
|
/** All GPU/canvas resources; call on world teardown. */
|
|
7381
7915
|
dispose() {
|
|
@@ -7384,84 +7918,188 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7384
7918
|
}
|
|
7385
7919
|
// ── Widgets ────────────────────────────────────────────────────────────────
|
|
7386
7920
|
syncPanel(world, entityId, panel) {
|
|
7387
|
-
const
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7921
|
+
const chrome = resolveChrome(
|
|
7922
|
+
panel,
|
|
7923
|
+
panel.style,
|
|
7924
|
+
this.tokensFor(world, entityId)
|
|
7925
|
+
);
|
|
7926
|
+
const bleed = chromeBleed(chrome);
|
|
7927
|
+
const size = resolveCanvasSize(
|
|
7928
|
+
panel.width + bleed * 2,
|
|
7929
|
+
panel.height + bleed * 2,
|
|
7930
|
+
panel.pixelDensity
|
|
7931
|
+
);
|
|
7932
|
+
const signature = panelSignature(
|
|
7933
|
+
panel.width,
|
|
7934
|
+
panel.height,
|
|
7935
|
+
size,
|
|
7936
|
+
chrome,
|
|
7937
|
+
imagesLoaded(chrome)
|
|
7938
|
+
);
|
|
7939
|
+
this.rebuildIfChanged(
|
|
7940
|
+
world,
|
|
7941
|
+
entityId,
|
|
7942
|
+
signature,
|
|
7943
|
+
panel,
|
|
7944
|
+
bleed,
|
|
7945
|
+
size,
|
|
7946
|
+
(ctx) => {
|
|
7947
|
+
drawChrome(
|
|
7948
|
+
ctx,
|
|
7949
|
+
layoutBox(panel, bleed, size.density),
|
|
7950
|
+
size.density,
|
|
7951
|
+
chrome,
|
|
7952
|
+
this.drawAssets
|
|
7953
|
+
);
|
|
7954
|
+
},
|
|
7955
|
+
THREE26.DoubleSide
|
|
7956
|
+
);
|
|
7399
7957
|
}
|
|
7400
7958
|
syncText(world, entityId, text) {
|
|
7401
|
-
const
|
|
7402
|
-
const
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
const signature =
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7959
|
+
const tokens = this.tokensFor(world, entityId);
|
|
7960
|
+
const chrome = text.style ? resolveChrome(CLEAR_CHROME, text.style, tokens) : null;
|
|
7961
|
+
const bleed = chrome ? chromeBleed(chrome) : 0;
|
|
7962
|
+
const size = resolveCanvasSize(
|
|
7963
|
+
text.width + bleed * 2,
|
|
7964
|
+
text.height + bleed * 2,
|
|
7965
|
+
text.pixelDensity
|
|
7966
|
+
);
|
|
7967
|
+
const style = resolveText(text, text.style, tokens);
|
|
7968
|
+
const family = familyOf(style.font);
|
|
7969
|
+
const signature = JSON.stringify([
|
|
7970
|
+
textSignature(text.width, text.height, size, text.text, style, family),
|
|
7971
|
+
chrome,
|
|
7972
|
+
chrome ? imagesLoaded(chrome) : null
|
|
7973
|
+
]);
|
|
7974
|
+
this.rebuildIfChanged(
|
|
7975
|
+
world,
|
|
7976
|
+
entityId,
|
|
7977
|
+
signature,
|
|
7978
|
+
text,
|
|
7979
|
+
bleed,
|
|
7980
|
+
size,
|
|
7981
|
+
(ctx) => {
|
|
7982
|
+
const box = layoutBox(text, bleed, size.density);
|
|
7983
|
+
if (chrome) {
|
|
7984
|
+
drawChrome(ctx, box, size.density, chrome, this.drawAssets);
|
|
7985
|
+
}
|
|
7986
|
+
drawTextBlock(
|
|
7987
|
+
ctx,
|
|
7988
|
+
box,
|
|
7989
|
+
size.density,
|
|
7990
|
+
text.text,
|
|
7991
|
+
style,
|
|
7992
|
+
family,
|
|
7993
|
+
this.drawAssets
|
|
7994
|
+
);
|
|
7995
|
+
}
|
|
7996
|
+
);
|
|
7416
7997
|
}
|
|
7417
7998
|
syncButton(world, entityId, button) {
|
|
7418
|
-
const
|
|
7419
|
-
const chrome =
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
const label =
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7999
|
+
const tokens = this.tokensFor(world, entityId);
|
|
8000
|
+
const chrome = resolveChrome(button, button.style, tokens);
|
|
8001
|
+
const bleed = chromeBleed(chrome);
|
|
8002
|
+
const size = resolveCanvasSize(
|
|
8003
|
+
button.width + bleed * 2,
|
|
8004
|
+
button.height + bleed * 2,
|
|
8005
|
+
button.pixelDensity
|
|
8006
|
+
);
|
|
8007
|
+
const label = resolveText(
|
|
8008
|
+
{
|
|
8009
|
+
fontSize: button.fontSize,
|
|
8010
|
+
fontWeight: button.fontWeight,
|
|
8011
|
+
color: button.textColor,
|
|
8012
|
+
align: "center",
|
|
8013
|
+
valign: "middle",
|
|
8014
|
+
lineHeight: 1.2,
|
|
8015
|
+
padding: 0.01
|
|
8016
|
+
},
|
|
8017
|
+
button.style,
|
|
8018
|
+
tokens
|
|
8019
|
+
);
|
|
8020
|
+
const family = familyOf(label.font);
|
|
8021
|
+
const icon = button.icon ? resolveToken(button.icon, tokens) : null;
|
|
7435
8022
|
const signature = buttonSignature(
|
|
7436
8023
|
button.width,
|
|
7437
8024
|
button.height,
|
|
7438
8025
|
size,
|
|
7439
8026
|
chrome,
|
|
7440
8027
|
button.label,
|
|
7441
|
-
label
|
|
8028
|
+
label,
|
|
8029
|
+
family,
|
|
8030
|
+
[imagesLoaded(chrome), icon, icon ? !!uiImage(icon) : false]
|
|
8031
|
+
);
|
|
8032
|
+
this.rebuildIfChanged(
|
|
8033
|
+
world,
|
|
8034
|
+
entityId,
|
|
8035
|
+
signature,
|
|
8036
|
+
button,
|
|
8037
|
+
bleed,
|
|
8038
|
+
size,
|
|
8039
|
+
(ctx) => {
|
|
8040
|
+
const box = layoutBox(button, bleed, size.density);
|
|
8041
|
+
drawChrome(ctx, box, size.density, chrome, this.drawAssets);
|
|
8042
|
+
if (icon) {
|
|
8043
|
+
drawIconLabel(
|
|
8044
|
+
ctx,
|
|
8045
|
+
box,
|
|
8046
|
+
size.density,
|
|
8047
|
+
button.label,
|
|
8048
|
+
label,
|
|
8049
|
+
family,
|
|
8050
|
+
icon,
|
|
8051
|
+
button.iconPosition ?? "left",
|
|
8052
|
+
this.drawAssets
|
|
8053
|
+
);
|
|
8054
|
+
} else {
|
|
8055
|
+
drawTextBlock(
|
|
8056
|
+
ctx,
|
|
8057
|
+
box,
|
|
8058
|
+
size.density,
|
|
8059
|
+
button.label,
|
|
8060
|
+
label,
|
|
8061
|
+
family,
|
|
8062
|
+
this.drawAssets
|
|
8063
|
+
);
|
|
8064
|
+
}
|
|
8065
|
+
}
|
|
7442
8066
|
);
|
|
7443
|
-
this.rebuildIfChanged(world, entityId, signature, button.width, button.height, size, (ctx) => {
|
|
7444
|
-
drawChrome(ctx, size.pxWidth, size.pxHeight, size.density, chrome);
|
|
7445
|
-
drawTextBlock(ctx, size.pxWidth, size.pxHeight, size.density, button.label, label);
|
|
7446
|
-
});
|
|
7447
8067
|
}
|
|
7448
8068
|
syncToggle(world, entityId, toggle, deltaTime) {
|
|
7449
|
-
const
|
|
7450
|
-
const
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
8069
|
+
const tokens = this.tokensFor(world, entityId);
|
|
8070
|
+
const accent = resolveToken(toggle.accentColor, tokens);
|
|
8071
|
+
const track = resolveToken(toggle.trackColor, tokens);
|
|
8072
|
+
const knobColor = resolveToken(toggle.knobColor, tokens);
|
|
8073
|
+
const size = resolveCanvasSize(
|
|
8074
|
+
toggle.width,
|
|
8075
|
+
toggle.height,
|
|
8076
|
+
toggle.pixelDensity
|
|
8077
|
+
);
|
|
8078
|
+
const variant = toggle.variant ?? "switch";
|
|
8079
|
+
if (variant !== "switch") {
|
|
8080
|
+
this.syncMarkToggle(world, entityId, toggle, accent, track, knobColor);
|
|
8081
|
+
return;
|
|
8082
|
+
}
|
|
8083
|
+
const chrome = resolveChrome(
|
|
8084
|
+
{
|
|
8085
|
+
backgroundColor: toggle.value ? accent : track,
|
|
8086
|
+
backgroundOpacity: 1,
|
|
8087
|
+
cornerRadius: toggle.height / 2,
|
|
8088
|
+
borderWidth: 0,
|
|
8089
|
+
borderColor: "#000000"
|
|
8090
|
+
},
|
|
8091
|
+
toggle.style,
|
|
8092
|
+
tokens
|
|
8093
|
+
);
|
|
7457
8094
|
const signature = JSON.stringify([
|
|
7458
8095
|
trackSignature(
|
|
7459
8096
|
toggle.width,
|
|
7460
8097
|
toggle.height,
|
|
7461
8098
|
size,
|
|
7462
8099
|
chrome,
|
|
7463
|
-
|
|
7464
|
-
|
|
8100
|
+
accent,
|
|
8101
|
+
knobColor,
|
|
8102
|
+
variant
|
|
7465
8103
|
),
|
|
7466
8104
|
toggle.value
|
|
7467
8105
|
]);
|
|
@@ -7469,18 +8107,24 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7469
8107
|
world,
|
|
7470
8108
|
entityId,
|
|
7471
8109
|
signature,
|
|
7472
|
-
toggle
|
|
7473
|
-
|
|
8110
|
+
toggle,
|
|
8111
|
+
0,
|
|
7474
8112
|
size,
|
|
7475
8113
|
(ctx) => {
|
|
7476
|
-
drawChrome(
|
|
8114
|
+
drawChrome(
|
|
8115
|
+
ctx,
|
|
8116
|
+
layoutBox(toggle, 0, size.density),
|
|
8117
|
+
size.density,
|
|
8118
|
+
chrome,
|
|
8119
|
+
this.drawAssets
|
|
8120
|
+
);
|
|
7477
8121
|
}
|
|
7478
8122
|
);
|
|
7479
8123
|
if (!entry) return;
|
|
7480
8124
|
if (!entry.knob) {
|
|
7481
8125
|
entry.knob = this.makeDisc(
|
|
7482
8126
|
toggle.height * 0.4,
|
|
7483
|
-
|
|
8127
|
+
knobColor,
|
|
7484
8128
|
entry.face.parent,
|
|
7485
8129
|
CHILD_Z
|
|
7486
8130
|
);
|
|
@@ -7492,35 +8136,95 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7492
8136
|
knob.position.x += (target - knob.position.x) * (deltaTime > 0 ? ease : 1);
|
|
7493
8137
|
knob.position.z = CHILD_Z;
|
|
7494
8138
|
}
|
|
8139
|
+
/** Checkbox and radio: a box or ring at the left of the widget's area. */
|
|
8140
|
+
syncMarkToggle(world, entityId, toggle, accent, track, markColor) {
|
|
8141
|
+
const tokens = this.tokensFor(world, entityId);
|
|
8142
|
+
const radio = toggle.variant === "radio";
|
|
8143
|
+
const size = resolveCanvasSize(
|
|
8144
|
+
toggle.width,
|
|
8145
|
+
toggle.height,
|
|
8146
|
+
toggle.pixelDensity
|
|
8147
|
+
);
|
|
8148
|
+
const side = toggle.height;
|
|
8149
|
+
const chrome = resolveChrome(
|
|
8150
|
+
{
|
|
8151
|
+
backgroundColor: toggle.value ? accent : track,
|
|
8152
|
+
backgroundOpacity: 1,
|
|
8153
|
+
cornerRadius: radio ? side / 2 : side * 0.2,
|
|
8154
|
+
borderWidth: 0,
|
|
8155
|
+
borderColor: "#000000"
|
|
8156
|
+
},
|
|
8157
|
+
toggle.style,
|
|
8158
|
+
tokens
|
|
8159
|
+
);
|
|
8160
|
+
const signature = JSON.stringify([
|
|
8161
|
+
trackSignature(
|
|
8162
|
+
toggle.width,
|
|
8163
|
+
toggle.height,
|
|
8164
|
+
size,
|
|
8165
|
+
chrome,
|
|
8166
|
+
accent,
|
|
8167
|
+
markColor,
|
|
8168
|
+
toggle.variant ?? null
|
|
8169
|
+
),
|
|
8170
|
+
toggle.value
|
|
8171
|
+
]);
|
|
8172
|
+
this.rebuildIfChanged(world, entityId, signature, toggle, 0, size, (ctx) => {
|
|
8173
|
+
const px = side * size.density;
|
|
8174
|
+
const box = { x: 0, y: 0, w: px, h: px };
|
|
8175
|
+
drawChrome(ctx, box, size.density, chrome, this.drawAssets);
|
|
8176
|
+
if (!toggle.value) return;
|
|
8177
|
+
if (radio) drawDot(ctx, px / 2, px / 2, px * 0.24, markColor);
|
|
8178
|
+
else drawCheckMark(ctx, box, markColor);
|
|
8179
|
+
});
|
|
8180
|
+
}
|
|
7495
8181
|
syncSlider(world, entityId, slider) {
|
|
7496
|
-
const
|
|
8182
|
+
const tokens = this.tokensFor(world, entityId);
|
|
8183
|
+
const accent = resolveToken(slider.accentColor, tokens);
|
|
8184
|
+
const track = resolveToken(slider.trackColor, tokens);
|
|
8185
|
+
const knobColor = resolveToken(slider.knobColor, tokens);
|
|
8186
|
+
const size = resolveCanvasSize(
|
|
8187
|
+
slider.width,
|
|
8188
|
+
slider.height,
|
|
8189
|
+
slider.pixelDensity
|
|
8190
|
+
);
|
|
8191
|
+
const range = Math.max(1e-6, slider.max - slider.min);
|
|
8192
|
+
const t = Math.min(1, Math.max(0, (slider.value - slider.min) / range));
|
|
8193
|
+
if (slider.variant === "progress" || slider.variant === "ring") {
|
|
8194
|
+
this.syncMeter(world, entityId, slider, t, accent, track, knobColor);
|
|
8195
|
+
return;
|
|
8196
|
+
}
|
|
7497
8197
|
const trackThickness = slider.height * 0.32;
|
|
7498
8198
|
const knobRadius = slider.height * 0.45;
|
|
7499
8199
|
const usable = Math.max(1e-3, slider.width - slider.height);
|
|
7500
|
-
const chrome =
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
8200
|
+
const chrome = resolveChrome(
|
|
8201
|
+
{
|
|
8202
|
+
backgroundColor: track,
|
|
8203
|
+
backgroundOpacity: 1,
|
|
8204
|
+
cornerRadius: trackThickness / 2,
|
|
8205
|
+
borderWidth: 0,
|
|
8206
|
+
borderColor: "#000000"
|
|
8207
|
+
},
|
|
8208
|
+
void 0,
|
|
8209
|
+
null
|
|
8210
|
+
);
|
|
7507
8211
|
const signature = trackSignature(
|
|
7508
8212
|
slider.width,
|
|
7509
8213
|
slider.height,
|
|
7510
8214
|
size,
|
|
7511
8215
|
chrome,
|
|
7512
|
-
|
|
7513
|
-
|
|
8216
|
+
accent,
|
|
8217
|
+
knobColor,
|
|
8218
|
+
slider.variant ?? null
|
|
7514
8219
|
);
|
|
7515
8220
|
const entry = this.rebuildIfChanged(
|
|
7516
8221
|
world,
|
|
7517
8222
|
entityId,
|
|
7518
8223
|
signature,
|
|
7519
|
-
slider
|
|
7520
|
-
|
|
8224
|
+
slider,
|
|
8225
|
+
0,
|
|
7521
8226
|
size,
|
|
7522
8227
|
(ctx) => {
|
|
7523
|
-
ctx.clearRect(0, 0, size.pxWidth, size.pxHeight);
|
|
7524
8228
|
const trackWidthM = usable + trackThickness;
|
|
7525
8229
|
drawRoundedBar(
|
|
7526
8230
|
ctx,
|
|
@@ -7528,7 +8232,7 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7528
8232
|
(slider.height - trackThickness) / 2 * size.density,
|
|
7529
8233
|
trackWidthM * size.density,
|
|
7530
8234
|
trackThickness * size.density,
|
|
7531
|
-
|
|
8235
|
+
track
|
|
7532
8236
|
);
|
|
7533
8237
|
}
|
|
7534
8238
|
);
|
|
@@ -7537,13 +8241,13 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7537
8241
|
entry.fill = this.makeQuad(
|
|
7538
8242
|
1,
|
|
7539
8243
|
trackThickness,
|
|
7540
|
-
|
|
8244
|
+
accent,
|
|
7541
8245
|
entry.face.parent,
|
|
7542
8246
|
CHILD_Z / 2
|
|
7543
8247
|
);
|
|
7544
8248
|
entry.cap = this.makeDisc(
|
|
7545
8249
|
trackThickness / 2,
|
|
7546
|
-
|
|
8250
|
+
accent,
|
|
7547
8251
|
entry.face.parent,
|
|
7548
8252
|
CHILD_Z / 2,
|
|
7549
8253
|
Math.PI / 2,
|
|
@@ -7554,51 +8258,124 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7554
8258
|
if (!entry.knob) {
|
|
7555
8259
|
entry.knob = this.makeDisc(
|
|
7556
8260
|
knobRadius,
|
|
7557
|
-
|
|
8261
|
+
knobColor,
|
|
7558
8262
|
entry.face.parent,
|
|
7559
8263
|
CHILD_Z
|
|
7560
8264
|
);
|
|
7561
8265
|
}
|
|
7562
|
-
const range = Math.max(1e-6, slider.max - slider.min);
|
|
7563
|
-
const t = Math.min(1, Math.max(0, (slider.value - slider.min) / range));
|
|
7564
8266
|
entry.knob.position.x = -usable / 2 + t * usable;
|
|
7565
8267
|
entry.knob.position.z = CHILD_Z;
|
|
7566
8268
|
entry.fill.scale.x = Math.max(1e-4, t * usable);
|
|
7567
8269
|
entry.fill.position.x = -usable / 2 + t * usable / 2;
|
|
7568
8270
|
entry.fill.position.z = CHILD_Z / 2;
|
|
7569
8271
|
}
|
|
8272
|
+
/**
|
|
8273
|
+
* Progress bars and rings. Unlike a slider these change rarely and have no
|
|
8274
|
+
* drag to keep smooth, so the value is drawn, in steps of half a percent.
|
|
8275
|
+
*/
|
|
8276
|
+
syncMeter(world, entityId, slider, t, accent, track, knobColor) {
|
|
8277
|
+
const size = resolveCanvasSize(
|
|
8278
|
+
slider.width,
|
|
8279
|
+
slider.height,
|
|
8280
|
+
slider.pixelDensity
|
|
8281
|
+
);
|
|
8282
|
+
const shown = Math.round(t * METER_STEPS) / METER_STEPS;
|
|
8283
|
+
const signature = JSON.stringify([
|
|
8284
|
+
slider.width,
|
|
8285
|
+
slider.height,
|
|
8286
|
+
size,
|
|
8287
|
+
slider.variant,
|
|
8288
|
+
accent,
|
|
8289
|
+
track,
|
|
8290
|
+
knobColor,
|
|
8291
|
+
shown
|
|
8292
|
+
]);
|
|
8293
|
+
this.rebuildIfChanged(world, entityId, signature, slider, 0, size, (ctx) => {
|
|
8294
|
+
const box = {
|
|
8295
|
+
x: 0,
|
|
8296
|
+
y: 0,
|
|
8297
|
+
w: size.pxWidth,
|
|
8298
|
+
h: size.pxHeight
|
|
8299
|
+
};
|
|
8300
|
+
if (slider.variant === "ring") {
|
|
8301
|
+
drawRing(ctx, box, shown, track, accent);
|
|
8302
|
+
return;
|
|
8303
|
+
}
|
|
8304
|
+
drawRoundedBar(ctx, 0, 0, box.w, box.h, track);
|
|
8305
|
+
if (shown <= 0) return;
|
|
8306
|
+
const fill = Math.max(box.h, box.w * shown);
|
|
8307
|
+
drawRoundedBar(ctx, 0, 0, fill, box.h, accent);
|
|
8308
|
+
});
|
|
8309
|
+
}
|
|
8310
|
+
/** The tokens in scope for a widget, nearest panel first. */
|
|
8311
|
+
tokensFor(world, entityId) {
|
|
8312
|
+
if (!this.anyTokens) return null;
|
|
8313
|
+
let merged = null;
|
|
8314
|
+
const visited = /* @__PURE__ */ new Set();
|
|
8315
|
+
let current = entityId;
|
|
8316
|
+
while (current !== null && !visited.has(current)) {
|
|
8317
|
+
visited.add(current);
|
|
8318
|
+
const tokens = world.getComponent(current, UIPanelComponent)?.tokens;
|
|
8319
|
+
if (tokens) merged = { ...tokens, ...merged ?? {} };
|
|
8320
|
+
const parent = world.getComponent(current, ParentId)?.value;
|
|
8321
|
+
current = typeof parent === "number" ? parent : null;
|
|
8322
|
+
}
|
|
8323
|
+
return merged;
|
|
8324
|
+
}
|
|
7570
8325
|
// ── Machinery ──────────────────────────────────────────────────────────────
|
|
7571
|
-
rebuildIfChanged(world, entityId, signature,
|
|
8326
|
+
rebuildIfChanged(world, entityId, signature, widget, bleed, size, draw, side = THREE26.FrontSide) {
|
|
7572
8327
|
const root = world.getComponent(entityId, Object3DRef)?.object;
|
|
7573
8328
|
if (!root) return null;
|
|
8329
|
+
const widthM = widget.width;
|
|
8330
|
+
const heightM = widget.height;
|
|
8331
|
+
const faceWidth = widthM + bleed * 2;
|
|
8332
|
+
const faceHeight = heightM + bleed * 2;
|
|
7574
8333
|
let entry = this.entries.get(entityId);
|
|
8334
|
+
if (entry) entry.opacity = widget.style?.opacity ?? 1;
|
|
7575
8335
|
if (entry && entry.signature === signature) return entry;
|
|
7576
8336
|
if (entry) this.disposeMovingParts(entry);
|
|
7577
8337
|
if (!entry) {
|
|
7578
8338
|
const canvas2 = this.createCanvas();
|
|
7579
|
-
const texture = new
|
|
8339
|
+
const texture = new THREE26.CanvasTexture(
|
|
7580
8340
|
canvas2
|
|
7581
8341
|
);
|
|
7582
8342
|
this.configureTexture(world, texture);
|
|
7583
|
-
const material = new
|
|
8343
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
7584
8344
|
map: texture,
|
|
7585
8345
|
transparent: true,
|
|
7586
8346
|
depthWrite: false,
|
|
7587
8347
|
// UI colours are authored absolutes; scene tone mapping would shift
|
|
7588
8348
|
// them (the classic "why is my white UI beige" bug).
|
|
7589
8349
|
toneMapped: false,
|
|
7590
|
-
side
|
|
7591
|
-
premultipliedAlpha:
|
|
8350
|
+
side,
|
|
8351
|
+
premultipliedAlpha: false,
|
|
8352
|
+
blending: THREE26.CustomBlending,
|
|
8353
|
+
blendSrc: THREE26.OneFactor,
|
|
8354
|
+
blendDst: THREE26.OneMinusSrcAlphaFactor,
|
|
8355
|
+
blendSrcAlpha: THREE26.OneFactor,
|
|
8356
|
+
blendDstAlpha: THREE26.OneMinusSrcAlphaFactor
|
|
7592
8357
|
});
|
|
7593
|
-
const face = new
|
|
7594
|
-
new
|
|
8358
|
+
const face = new THREE26.Mesh(
|
|
8359
|
+
new THREE26.PlaneGeometry(faceWidth, faceHeight),
|
|
7595
8360
|
material
|
|
7596
8361
|
);
|
|
7597
|
-
face
|
|
8362
|
+
tagPart(face, 16777215, true);
|
|
8363
|
+
face.raycast = () => {
|
|
8364
|
+
};
|
|
7598
8365
|
root.add(face);
|
|
8366
|
+
const hit = new THREE26.Mesh(
|
|
8367
|
+
new THREE26.PlaneGeometry(widthM, heightM),
|
|
8368
|
+
new THREE26.MeshBasicMaterial({ visible: false, side })
|
|
8369
|
+
);
|
|
8370
|
+
root.add(hit);
|
|
7599
8371
|
entry = {
|
|
7600
8372
|
signature: "",
|
|
8373
|
+
root,
|
|
8374
|
+
width: widthM,
|
|
8375
|
+
height: heightM,
|
|
8376
|
+
opacity: widget.style?.opacity ?? 1,
|
|
7601
8377
|
face,
|
|
8378
|
+
hit,
|
|
7602
8379
|
texture,
|
|
7603
8380
|
material,
|
|
7604
8381
|
canvas: canvas2,
|
|
@@ -7612,23 +8389,26 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7612
8389
|
if (canvas.width !== size.pxWidth || canvas.height !== size.pxHeight) {
|
|
7613
8390
|
canvas.width = size.pxWidth;
|
|
7614
8391
|
canvas.height = size.pxHeight;
|
|
8392
|
+
if (entry.signature) entry.texture.dispose();
|
|
7615
8393
|
}
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
}
|
|
8394
|
+
entry.width = widthM;
|
|
8395
|
+
entry.height = heightM;
|
|
8396
|
+
resizePlane(entry.face, faceWidth, faceHeight);
|
|
8397
|
+
resizePlane(entry.hit, widthM, heightM);
|
|
7621
8398
|
const ctx = canvas.getContext("2d");
|
|
7622
|
-
if (ctx)
|
|
8399
|
+
if (ctx) {
|
|
8400
|
+
ctx.clearRect(0, 0, size.pxWidth, size.pxHeight);
|
|
8401
|
+
draw(ctx);
|
|
8402
|
+
}
|
|
7623
8403
|
entry.texture.needsUpdate = true;
|
|
7624
8404
|
entry.signature = signature;
|
|
7625
8405
|
return entry;
|
|
7626
8406
|
}
|
|
7627
8407
|
configureTexture(world, texture) {
|
|
7628
|
-
texture.colorSpace =
|
|
8408
|
+
texture.colorSpace = THREE26.SRGBColorSpace;
|
|
7629
8409
|
texture.generateMipmaps = true;
|
|
7630
|
-
texture.minFilter =
|
|
7631
|
-
texture.magFilter =
|
|
8410
|
+
texture.minFilter = THREE26.LinearMipmapLinearFilter;
|
|
8411
|
+
texture.magFilter = THREE26.LinearFilter;
|
|
7632
8412
|
texture.premultiplyAlpha = true;
|
|
7633
8413
|
try {
|
|
7634
8414
|
const renderer = world.getRenderer();
|
|
@@ -7639,7 +8419,7 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7639
8419
|
}
|
|
7640
8420
|
makeQuad(widthM, heightM, color, parent, z) {
|
|
7641
8421
|
return this.addPart(
|
|
7642
|
-
new
|
|
8422
|
+
new THREE26.PlaneGeometry(widthM, heightM),
|
|
7643
8423
|
color,
|
|
7644
8424
|
parent,
|
|
7645
8425
|
z
|
|
@@ -7648,24 +8428,23 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7648
8428
|
/** A filled disc (or arc segment, for the fill's rounded cap). */
|
|
7649
8429
|
makeDisc(radiusM, color, parent, z, thetaStart = 0, thetaLength = Math.PI * 2) {
|
|
7650
8430
|
return this.addPart(
|
|
7651
|
-
new
|
|
8431
|
+
new THREE26.CircleGeometry(radiusM, 32, thetaStart, thetaLength),
|
|
7652
8432
|
color,
|
|
7653
8433
|
parent,
|
|
7654
8434
|
z
|
|
7655
8435
|
);
|
|
7656
8436
|
}
|
|
7657
8437
|
addPart(geometry, color, parent, z) {
|
|
7658
|
-
const mesh = new
|
|
8438
|
+
const mesh = new THREE26.Mesh(
|
|
7659
8439
|
geometry,
|
|
7660
|
-
new
|
|
8440
|
+
new THREE26.MeshBasicMaterial({
|
|
7661
8441
|
color,
|
|
7662
8442
|
transparent: true,
|
|
7663
8443
|
depthWrite: false,
|
|
7664
|
-
toneMapped: false
|
|
7665
|
-
side: THREE19.DoubleSide
|
|
8444
|
+
toneMapped: false
|
|
7666
8445
|
})
|
|
7667
8446
|
);
|
|
7668
|
-
mesh
|
|
8447
|
+
tagPart(mesh, color);
|
|
7669
8448
|
mesh.position.z = z;
|
|
7670
8449
|
mesh.raycast = () => {
|
|
7671
8450
|
};
|
|
@@ -7696,22 +8475,144 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7696
8475
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
7697
8476
|
if (!transform || !object) return;
|
|
7698
8477
|
const camera = world.getCamera();
|
|
7699
|
-
const cam = new
|
|
7700
|
-
const self = new
|
|
8478
|
+
const cam = new THREE26.Vector3();
|
|
8479
|
+
const self = new THREE26.Vector3();
|
|
7701
8480
|
camera.getWorldPosition(cam);
|
|
7702
8481
|
object.getWorldPosition(self);
|
|
7703
8482
|
transform.rotation.y = Math.atan2(cam.x - self.x, cam.z - self.z);
|
|
7704
8483
|
}
|
|
8484
|
+
/**
|
|
8485
|
+
* Stamp every widget's meshes with this frame's paint order. Written each
|
|
8486
|
+
* frame because the eye moves: the order between trees can change at any
|
|
8487
|
+
* time, and a plain property write costs less than checking it.
|
|
8488
|
+
*/
|
|
8489
|
+
applyPaintOrder(world) {
|
|
8490
|
+
if (this.entries.size === 0) return;
|
|
8491
|
+
const camera = world.getCamera();
|
|
8492
|
+
camera.getWorldPosition(eyeScratch);
|
|
8493
|
+
const nodes = [...this.entries.keys()].map((id) => ({
|
|
8494
|
+
id,
|
|
8495
|
+
parent: nearestWidgetAncestor(world, id)
|
|
8496
|
+
}));
|
|
8497
|
+
const trees = buildPaintTrees(nodes);
|
|
8498
|
+
const rects = /* @__PURE__ */ new Map();
|
|
8499
|
+
for (const tree of trees) {
|
|
8500
|
+
const entry = this.entries.get(tree.rootId);
|
|
8501
|
+
if (entry) rects.set(tree.rootId, rootRect(tree.rootId, entry));
|
|
8502
|
+
}
|
|
8503
|
+
const slots = assignPaintOrder(trees, rects, eyeScratch);
|
|
8504
|
+
this.framesUntilDescendantWalk -= 1;
|
|
8505
|
+
const walkDescendants = this.framesUntilDescendantWalk <= 0;
|
|
8506
|
+
if (walkDescendants) {
|
|
8507
|
+
this.framesUntilDescendantWalk = DESCENDANT_WALK_INTERVAL;
|
|
8508
|
+
}
|
|
8509
|
+
const widgetRoots = /* @__PURE__ */ new Set();
|
|
8510
|
+
if (walkDescendants) {
|
|
8511
|
+
for (const entry of this.entries.values()) widgetRoots.add(entry.root);
|
|
8512
|
+
}
|
|
8513
|
+
for (const [entityId, entry] of this.entries) {
|
|
8514
|
+
const slot = slots.get(entityId);
|
|
8515
|
+
if (!slot) continue;
|
|
8516
|
+
entry.face.renderOrder = slot.face;
|
|
8517
|
+
for (const part of [entry.knob, entry.fill, entry.cap]) {
|
|
8518
|
+
if (part) part.renderOrder = slot.parts;
|
|
8519
|
+
}
|
|
8520
|
+
if (walkDescendants) stampDescendants(entry.root, slot, widgetRoots);
|
|
8521
|
+
}
|
|
8522
|
+
const effective = /* @__PURE__ */ new Map();
|
|
8523
|
+
const parentOf = new Map(nodes.map((node) => [node.id, node.parent]));
|
|
8524
|
+
for (const tree of trees) {
|
|
8525
|
+
for (const id of tree.order) {
|
|
8526
|
+
const entry = this.entries.get(id);
|
|
8527
|
+
if (!entry) continue;
|
|
8528
|
+
const parent = parentOf.get(id);
|
|
8529
|
+
const inherited = parent != null ? effective.get(parent) ?? 1 : 1;
|
|
8530
|
+
const opacity = entry.opacity * inherited;
|
|
8531
|
+
effective.set(id, opacity);
|
|
8532
|
+
for (const mesh of [entry.face, entry.knob, entry.fill, entry.cap]) {
|
|
8533
|
+
if (!mesh) continue;
|
|
8534
|
+
const tag = mesh.userData[UI_PART_KEY];
|
|
8535
|
+
if (tag.opacity === opacity) continue;
|
|
8536
|
+
tag.opacity = opacity;
|
|
8537
|
+
applyPartColor(mesh, tag);
|
|
8538
|
+
}
|
|
8539
|
+
}
|
|
8540
|
+
}
|
|
8541
|
+
}
|
|
7705
8542
|
destroyEntry(entry) {
|
|
7706
8543
|
this.disposeMovingParts(entry);
|
|
7707
8544
|
entry.face.removeFromParent();
|
|
7708
8545
|
entry.face.geometry.dispose();
|
|
7709
8546
|
entry.face.material.dispose();
|
|
8547
|
+
entry.hit.removeFromParent();
|
|
8548
|
+
entry.hit.geometry.dispose();
|
|
8549
|
+
entry.hit.material.dispose();
|
|
7710
8550
|
entry.texture.dispose();
|
|
7711
8551
|
}
|
|
7712
8552
|
};
|
|
7713
8553
|
__name(_UIPanelSystem, "UIPanelSystem");
|
|
7714
8554
|
var UIPanelSystem = _UIPanelSystem;
|
|
8555
|
+
var eyeScratch = new THREE26.Vector3();
|
|
8556
|
+
function tagPart(mesh, color, premultiplied = false) {
|
|
8557
|
+
const tag = {
|
|
8558
|
+
baseColor: new THREE26.Color(color),
|
|
8559
|
+
tint: 1,
|
|
8560
|
+
opacity: 1,
|
|
8561
|
+
premultiplied
|
|
8562
|
+
};
|
|
8563
|
+
mesh.userData[UI_PART_KEY] = tag;
|
|
8564
|
+
}
|
|
8565
|
+
__name(tagPart, "tagPart");
|
|
8566
|
+
function resizePlane(mesh, width, height) {
|
|
8567
|
+
const params = mesh.geometry.parameters;
|
|
8568
|
+
if (params.width === width && params.height === height) return;
|
|
8569
|
+
mesh.geometry.dispose();
|
|
8570
|
+
mesh.geometry = new THREE26.PlaneGeometry(width, height);
|
|
8571
|
+
}
|
|
8572
|
+
__name(resizePlane, "resizePlane");
|
|
8573
|
+
function layoutBox(widget, bleed, density) {
|
|
8574
|
+
return {
|
|
8575
|
+
x: bleed * density,
|
|
8576
|
+
y: bleed * density,
|
|
8577
|
+
w: widget.width * density,
|
|
8578
|
+
h: widget.height * density
|
|
8579
|
+
};
|
|
8580
|
+
}
|
|
8581
|
+
__name(layoutBox, "layoutBox");
|
|
8582
|
+
function familyOf(font) {
|
|
8583
|
+
return font ? uiFontFamily(font) : null;
|
|
8584
|
+
}
|
|
8585
|
+
__name(familyOf, "familyOf");
|
|
8586
|
+
function imagesLoaded(chrome) {
|
|
8587
|
+
return styleAssets(chrome, null).images.map((src) => !!uiImage(src));
|
|
8588
|
+
}
|
|
8589
|
+
__name(imagesLoaded, "imagesLoaded");
|
|
8590
|
+
function rootRect(id, entry) {
|
|
8591
|
+
const e = entry.root.matrixWorld.elements;
|
|
8592
|
+
const halfW = entry.width / 2;
|
|
8593
|
+
const halfH = entry.height / 2;
|
|
8594
|
+
return {
|
|
8595
|
+
id,
|
|
8596
|
+
center: { x: e[12], y: e[13], z: e[14] },
|
|
8597
|
+
halfX: { x: e[0] * halfW, y: e[1] * halfW, z: e[2] * halfW },
|
|
8598
|
+
halfY: { x: e[4] * halfH, y: e[5] * halfH, z: e[6] * halfH }
|
|
8599
|
+
};
|
|
8600
|
+
}
|
|
8601
|
+
__name(rootRect, "rootRect");
|
|
8602
|
+
function stampDescendants(root, slot, widgetRoots) {
|
|
8603
|
+
for (const child of root.children) {
|
|
8604
|
+
if (widgetRoots.has(child) || child.userData[UI_PART_KEY]) continue;
|
|
8605
|
+
const material = child.material;
|
|
8606
|
+
const transparent = Array.isArray(material) ? material.some((m) => m.transparent) : material?.transparent === true;
|
|
8607
|
+
const untouched = child.renderOrder === 0 || child.userData[PAINT_STAMP_KEY] === child.renderOrder;
|
|
8608
|
+
if (transparent && untouched) {
|
|
8609
|
+
child.renderOrder = slot.descendants;
|
|
8610
|
+
child.userData[PAINT_STAMP_KEY] = slot.descendants;
|
|
8611
|
+
}
|
|
8612
|
+
stampDescendants(child, slot, widgetRoots);
|
|
8613
|
+
}
|
|
8614
|
+
}
|
|
8615
|
+
__name(stampDescendants, "stampDescendants");
|
|
7715
8616
|
var _XRHitTestSystem = class _XRHitTestSystem {
|
|
7716
8617
|
constructor() {
|
|
7717
8618
|
this.sources = /* @__PURE__ */ new Map();
|
|
@@ -7748,12 +8649,12 @@ var _XRHitTestSystem = class _XRHitTestSystem {
|
|
|
7748
8649
|
if (!hits || hits.length === 0) continue;
|
|
7749
8650
|
const pose = hits[0].getPose(referenceSpace);
|
|
7750
8651
|
if (!pose) continue;
|
|
7751
|
-
const matrix = new
|
|
8652
|
+
const matrix = new THREE26.Matrix4().fromArray(
|
|
7752
8653
|
pose.transform.matrix
|
|
7753
8654
|
);
|
|
7754
|
-
const position = new
|
|
7755
|
-
const quaternion = new
|
|
7756
|
-
matrix.decompose(position, quaternion, new
|
|
8655
|
+
const position = new THREE26.Vector3();
|
|
8656
|
+
const quaternion = new THREE26.Quaternion();
|
|
8657
|
+
matrix.decompose(position, quaternion, new THREE26.Vector3());
|
|
7757
8658
|
this.results.set(key, { position, quaternion });
|
|
7758
8659
|
}
|
|
7759
8660
|
}
|
|
@@ -7827,8 +8728,8 @@ var _XRAnchorSystem = class _XRAnchorSystem {
|
|
|
7827
8728
|
/** Per-anchor head-glue gates — see XREnvironmentSystem's TrackedEntry. */
|
|
7828
8729
|
this.gates = /* @__PURE__ */ new Map();
|
|
7829
8730
|
this.presenting = false;
|
|
7830
|
-
this.tmpViewerMatrix = new
|
|
7831
|
-
this.tmpViewPos = new
|
|
8731
|
+
this.tmpViewerMatrix = new THREE26.Matrix4();
|
|
8732
|
+
this.tmpViewPos = new THREE26.Vector3();
|
|
7832
8733
|
}
|
|
7833
8734
|
update(world, deltaTime = 0) {
|
|
7834
8735
|
const presenting = world.isXrPresenting();
|
|
@@ -7902,8 +8803,8 @@ var _XRAnchorSystem = class _XRAnchorSystem {
|
|
|
7902
8803
|
if (typeof frame.createAnchor !== "function") return;
|
|
7903
8804
|
const RigidTransform = globalThis.XRRigidTransform;
|
|
7904
8805
|
if (!RigidTransform) return;
|
|
7905
|
-
const quaternion = new
|
|
7906
|
-
new
|
|
8806
|
+
const quaternion = new THREE26.Quaternion().setFromEuler(
|
|
8807
|
+
new THREE26.Euler(
|
|
7907
8808
|
transform.rotation.x,
|
|
7908
8809
|
transform.rotation.y,
|
|
7909
8810
|
transform.rotation.z,
|
|
@@ -7946,13 +8847,13 @@ var _XRAnchorSystem = class _XRAnchorSystem {
|
|
|
7946
8847
|
};
|
|
7947
8848
|
__name(_XRAnchorSystem, "XRAnchorSystem");
|
|
7948
8849
|
var XRAnchorSystem = _XRAnchorSystem;
|
|
7949
|
-
var _q = new
|
|
7950
|
-
var _q2 = new
|
|
7951
|
-
var _s = new
|
|
7952
|
-
var _e = new
|
|
7953
|
-
var _w = new
|
|
7954
|
-
var _v = new
|
|
7955
|
-
var _p = new
|
|
8850
|
+
var _q = new THREE26.Quaternion();
|
|
8851
|
+
var _q2 = new THREE26.Quaternion();
|
|
8852
|
+
var _s = new THREE26.Vector3();
|
|
8853
|
+
var _e = new THREE26.Vector3();
|
|
8854
|
+
var _w = new THREE26.Vector3();
|
|
8855
|
+
var _v = new THREE26.Vector3();
|
|
8856
|
+
var _p = new THREE26.Vector3();
|
|
7956
8857
|
function setWorldQuaternion(o, q) {
|
|
7957
8858
|
if (o.parent) {
|
|
7958
8859
|
o.parent.getWorldQuaternion(_q2).invert();
|
|
@@ -7977,31 +8878,31 @@ function twoBoneIK(upper, lower, end, target, pole) {
|
|
|
7977
8878
|
if (a < 1e-6 || b < 1e-6) return target.distanceTo(_w);
|
|
7978
8879
|
const toT = _v.subVectors(target, _s);
|
|
7979
8880
|
const want = toT.length();
|
|
7980
|
-
const c =
|
|
8881
|
+
const c = THREE26.MathUtils.clamp(want, Math.abs(a - b) + 1e-4, a + b - 1e-4);
|
|
7981
8882
|
const dir = toT.divideScalar(want || 1).clone();
|
|
7982
8883
|
const pv = _p.subVectors(pole, _s);
|
|
7983
8884
|
pv.addScaledVector(dir, -pv.dot(dir));
|
|
7984
8885
|
if (pv.lengthSq() < 1e-8) pv.set(0, -1, 0).addScaledVector(dir, dir.y);
|
|
7985
8886
|
pv.normalize();
|
|
7986
|
-
const cosA =
|
|
8887
|
+
const cosA = THREE26.MathUtils.clamp((a * a + c * c - b * b) / (2 * a * c), -1, 1);
|
|
7987
8888
|
const joint = _s.clone().addScaledVector(dir, a * cosA).addScaledVector(pv, a * Math.sqrt(1 - cosA * cosA));
|
|
7988
|
-
turn(upper, new
|
|
8889
|
+
turn(upper, new THREE26.Quaternion().setFromUnitVectors(_e.clone().sub(_s).normalize(), joint.clone().sub(_s).normalize()));
|
|
7989
8890
|
lower.getWorldPosition(_e);
|
|
7990
8891
|
end.getWorldPosition(_w);
|
|
7991
8892
|
const reach = _s.clone().addScaledVector(dir, c);
|
|
7992
|
-
turn(lower, new
|
|
8893
|
+
turn(lower, new THREE26.Quaternion().setFromUnitVectors(_w.clone().sub(_e).normalize(), reach.clone().sub(_e).normalize()));
|
|
7993
8894
|
return want - c;
|
|
7994
8895
|
}
|
|
7995
8896
|
__name(twoBoneIK, "twoBoneIK");
|
|
7996
|
-
function gripQuaternion(axis, back, forearm, out = new
|
|
8897
|
+
function gripQuaternion(axis, back, forearm, out = new THREE26.Quaternion()) {
|
|
7997
8898
|
let X = axis.clone();
|
|
7998
8899
|
const Z = back.clone().addScaledVector(X, -back.dot(X)).normalize().negate();
|
|
7999
|
-
let Y = new
|
|
8900
|
+
let Y = new THREE26.Vector3().crossVectors(Z, X);
|
|
8000
8901
|
if (Y.dot(forearm) < 0) {
|
|
8001
8902
|
X = X.negate();
|
|
8002
8903
|
Y = Y.negate();
|
|
8003
8904
|
}
|
|
8004
|
-
return out.setFromRotationMatrix(new
|
|
8905
|
+
return out.setFromRotationMatrix(new THREE26.Matrix4().makeBasis(X, Y, Z));
|
|
8005
8906
|
}
|
|
8006
8907
|
__name(gripQuaternion, "gripQuaternion");
|
|
8007
8908
|
|
|
@@ -8012,18 +8913,20 @@ var LIMB_BONES = {
|
|
|
8012
8913
|
leftFoot: ["leftUpperLeg", "leftLowerLeg", "leftFoot"],
|
|
8013
8914
|
rightFoot: ["rightUpperLeg", "rightLowerLeg", "rightFoot"]
|
|
8014
8915
|
};
|
|
8015
|
-
var _t = new
|
|
8016
|
-
var _p2 = new
|
|
8017
|
-
var _q3 = new
|
|
8018
|
-
var _pq = new
|
|
8916
|
+
var _t = new THREE26.Vector3();
|
|
8917
|
+
var _p2 = new THREE26.Vector3();
|
|
8918
|
+
var _q3 = new THREE26.Quaternion();
|
|
8919
|
+
var _pq = new THREE26.Quaternion();
|
|
8019
8920
|
var _IKSystem = class _IKSystem {
|
|
8020
8921
|
constructor() {
|
|
8021
8922
|
this.runtimes = /* @__PURE__ */ new Map();
|
|
8022
|
-
this.reach = /* @__PURE__ */ new Map();
|
|
8023
8923
|
}
|
|
8024
|
-
/**
|
|
8924
|
+
/**
|
|
8925
|
+
* How far a limb's end stayed from its target last frame, in metres
|
|
8926
|
+
* (0 = reached), or null if the limb's chain didn't run.
|
|
8927
|
+
*/
|
|
8025
8928
|
getReachError(entityId, limb) {
|
|
8026
|
-
return this.reach.get(
|
|
8929
|
+
return this.runtimes.get(entityId)?.reach.get(limb) ?? null;
|
|
8027
8930
|
}
|
|
8028
8931
|
restore(runtime) {
|
|
8029
8932
|
for (const [bone, w] of runtime.written) {
|
|
@@ -8049,13 +8952,14 @@ var _IKSystem = class _IKSystem {
|
|
|
8049
8952
|
let runtime = this.runtimes.get(id);
|
|
8050
8953
|
if (!runtime || runtime.rootUuid !== root.uuid) {
|
|
8051
8954
|
if (runtime) this.restore(runtime);
|
|
8052
|
-
runtime = { rootUuid: root.uuid, limbs: /* @__PURE__ */ new Map(), written: /* @__PURE__ */ new Map() };
|
|
8955
|
+
runtime = { rootUuid: root.uuid, limbs: /* @__PURE__ */ new Map(), written: /* @__PURE__ */ new Map(), reach: /* @__PURE__ */ new Map() };
|
|
8053
8956
|
this.runtimes.set(id, runtime);
|
|
8054
8957
|
}
|
|
8055
8958
|
for (const [bone, w] of runtime.written) {
|
|
8056
8959
|
if (bone.quaternion.equals(w.written)) bone.quaternion.copy(w.before);
|
|
8057
8960
|
}
|
|
8058
8961
|
runtime.written.clear();
|
|
8962
|
+
runtime.reach.clear();
|
|
8059
8963
|
if (!ik.enabled) continue;
|
|
8060
8964
|
const active = ik.chains.filter((c) => c.enabled && c.weight > 0 && typeof c.target === "number");
|
|
8061
8965
|
if (active.length === 0) continue;
|
|
@@ -8076,7 +8980,7 @@ var _IKSystem = class _IKSystem {
|
|
|
8076
8980
|
const [upper, lower, end] = limb.bones;
|
|
8077
8981
|
for (const bone of [upper, lower, end]) {
|
|
8078
8982
|
if (!runtime.written.has(bone)) {
|
|
8079
|
-
runtime.written.set(bone, { before: bone.quaternion.clone(), written: new
|
|
8983
|
+
runtime.written.set(bone, { before: bone.quaternion.clone(), written: new THREE26.Quaternion() });
|
|
8080
8984
|
}
|
|
8081
8985
|
}
|
|
8082
8986
|
const animated = [upper.quaternion.clone(), lower.quaternion.clone(), end.quaternion.clone()];
|
|
@@ -8085,7 +8989,7 @@ var _IKSystem = class _IKSystem {
|
|
|
8085
8989
|
if (poleObject) poleObject.getWorldPosition(_p2);
|
|
8086
8990
|
else lower.getWorldPosition(_p2);
|
|
8087
8991
|
const miss = twoBoneIK(upper, lower, end, _t, _p2);
|
|
8088
|
-
|
|
8992
|
+
runtime.reach.set(chain.limb, Math.max(0, miss));
|
|
8089
8993
|
if (chain.matchRotation) {
|
|
8090
8994
|
target.getWorldQuaternion(_q3);
|
|
8091
8995
|
end.parent?.getWorldQuaternion(_pq);
|
|
@@ -8114,9 +9018,9 @@ var IKSystem = _IKSystem;
|
|
|
8114
9018
|
function buildGeometry2(area) {
|
|
8115
9019
|
if (area.shape === "circle") {
|
|
8116
9020
|
const radius = Math.max(5e-3, area.width / 2);
|
|
8117
|
-
return new
|
|
9021
|
+
return new THREE26.CircleGeometry(radius, 48);
|
|
8118
9022
|
}
|
|
8119
|
-
return new
|
|
9023
|
+
return new THREE26.PlaneGeometry(
|
|
8120
9024
|
Math.max(0.01, area.width),
|
|
8121
9025
|
Math.max(0.01, area.depth)
|
|
8122
9026
|
);
|
|
@@ -8133,13 +9037,13 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
|
|
|
8133
9037
|
update(world) {
|
|
8134
9038
|
const entityIds = world.query(VRTeleportAreaComponent, Object3DRef);
|
|
8135
9039
|
const alive = new Set(entityIds);
|
|
8136
|
-
for (const
|
|
8137
|
-
if (!alive.has(
|
|
9040
|
+
for (const tracked2 of this.signatures.keys()) {
|
|
9041
|
+
if (!alive.has(tracked2)) this.signatures.delete(tracked2);
|
|
8138
9042
|
}
|
|
8139
9043
|
for (const entityId of entityIds) {
|
|
8140
9044
|
const area = world.getComponent(entityId, VRTeleportAreaComponent);
|
|
8141
9045
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
8142
|
-
if (!area || !(object instanceof
|
|
9046
|
+
if (!area || !(object instanceof THREE26.Mesh)) continue;
|
|
8143
9047
|
const signature = signatureOf(area);
|
|
8144
9048
|
if (this.signatures.get(entityId) === signature) continue;
|
|
8145
9049
|
this.signatures.set(entityId, signature);
|
|
@@ -8151,18 +9055,18 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
|
|
|
8151
9055
|
__name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
|
|
8152
9056
|
var VRTeleportAreaSystem = _VRTeleportAreaSystem;
|
|
8153
9057
|
function createHandMaterial(preset, options) {
|
|
8154
|
-
const color = new
|
|
9058
|
+
const color = new THREE26.Color(options.color);
|
|
8155
9059
|
switch (preset) {
|
|
8156
9060
|
case "ghost":
|
|
8157
|
-
return new
|
|
9061
|
+
return new THREE26.MeshBasicMaterial({
|
|
8158
9062
|
color,
|
|
8159
9063
|
transparent: true,
|
|
8160
9064
|
opacity: Math.min(1, Math.max(0.05, options.opacity * 0.45)),
|
|
8161
9065
|
depthWrite: false,
|
|
8162
|
-
side:
|
|
9066
|
+
side: THREE26.DoubleSide
|
|
8163
9067
|
});
|
|
8164
9068
|
case "neon":
|
|
8165
|
-
return new
|
|
9069
|
+
return new THREE26.MeshStandardMaterial({
|
|
8166
9070
|
color,
|
|
8167
9071
|
emissive: color,
|
|
8168
9072
|
emissiveIntensity: Math.max(0.5, options.emissiveIntensity || 2),
|
|
@@ -8172,7 +9076,7 @@ function createHandMaterial(preset, options) {
|
|
|
8172
9076
|
opacity: options.opacity
|
|
8173
9077
|
});
|
|
8174
9078
|
case "skeleton":
|
|
8175
|
-
return new
|
|
9079
|
+
return new THREE26.MeshBasicMaterial({
|
|
8176
9080
|
color,
|
|
8177
9081
|
wireframe: true,
|
|
8178
9082
|
transparent: true,
|
|
@@ -8180,7 +9084,7 @@ function createHandMaterial(preset, options) {
|
|
|
8180
9084
|
});
|
|
8181
9085
|
case "custom":
|
|
8182
9086
|
case "default":
|
|
8183
|
-
return new
|
|
9087
|
+
return new THREE26.MeshStandardMaterial({
|
|
8184
9088
|
color,
|
|
8185
9089
|
roughness: 0.85,
|
|
8186
9090
|
metalness: 0,
|
|
@@ -8188,10 +9092,10 @@ function createHandMaterial(preset, options) {
|
|
|
8188
9092
|
emissiveIntensity: Math.max(0, options.emissiveIntensity),
|
|
8189
9093
|
transparent: options.opacity < 1,
|
|
8190
9094
|
opacity: options.opacity,
|
|
8191
|
-
side:
|
|
9095
|
+
side: THREE26.DoubleSide
|
|
8192
9096
|
});
|
|
8193
9097
|
default: {
|
|
8194
|
-
return new
|
|
9098
|
+
return new THREE26.MeshStandardMaterial({ color });
|
|
8195
9099
|
}
|
|
8196
9100
|
}
|
|
8197
9101
|
}
|
|
@@ -8216,9 +9120,9 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8216
9120
|
constructor(options) {
|
|
8217
9121
|
this.controllerModelFactory = new XRControllerModelFactory();
|
|
8218
9122
|
this.handModelFactory = new XRHandModelFactory();
|
|
8219
|
-
this.group = new
|
|
9123
|
+
this.group = new THREE26.Group();
|
|
8220
9124
|
/** Reused so a per-frame colour compare allocates nothing. */
|
|
8221
|
-
this.rayColorScratch = new
|
|
9125
|
+
this.rayColorScratch = new THREE26.Color();
|
|
8222
9126
|
this.slots = /* @__PURE__ */ new Map();
|
|
8223
9127
|
this.attachedTo = null;
|
|
8224
9128
|
/** Last applied preset signature, so materials rebuild only on real change. */
|
|
@@ -8355,8 +9259,8 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8355
9259
|
*/
|
|
8356
9260
|
fitRayToHover(ray, side) {
|
|
8357
9261
|
const hover = this.interactionSystem?.getHoverFor(side) ?? null;
|
|
8358
|
-
const
|
|
8359
|
-
ray.scale.z =
|
|
9262
|
+
const length2 = hover && Number.isFinite(hover.distance) && hover.distance > 0 ? Math.min(hover.distance, RAY_LENGTH) : RAY_LENGTH;
|
|
9263
|
+
ray.scale.z = length2;
|
|
8360
9264
|
}
|
|
8361
9265
|
/** Lazily build per-slot visuals; the device reports profiles late. */
|
|
8362
9266
|
ensureSlots(world) {
|
|
@@ -8405,17 +9309,17 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8405
9309
|
* without pulling in a line-rendering extension.
|
|
8406
9310
|
*/
|
|
8407
9311
|
createRay() {
|
|
8408
|
-
const geometry = new
|
|
9312
|
+
const geometry = new THREE26.CylinderGeometry(RAY_RADIUS, RAY_RADIUS, 1, 8, 1);
|
|
8409
9313
|
geometry.rotateX(-Math.PI / 2);
|
|
8410
9314
|
geometry.translate(0, 0, -0.5);
|
|
8411
|
-
const material = new
|
|
9315
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
8412
9316
|
color: "#4da3ff",
|
|
8413
9317
|
transparent: true,
|
|
8414
9318
|
opacity: 0.75,
|
|
8415
9319
|
depthTest: false,
|
|
8416
9320
|
depthWrite: false
|
|
8417
9321
|
});
|
|
8418
|
-
const mesh = new
|
|
9322
|
+
const mesh = new THREE26.Mesh(geometry, material);
|
|
8419
9323
|
mesh.name = "XRPointerRay";
|
|
8420
9324
|
mesh.renderOrder = 999;
|
|
8421
9325
|
mesh.visible = false;
|
|
@@ -8446,14 +9350,14 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8446
9350
|
__name(_XRControllerVisualSystem, "XRControllerVisualSystem");
|
|
8447
9351
|
var XRControllerVisualSystem = _XRControllerVisualSystem;
|
|
8448
9352
|
var MARKER_RADIUS = 0.28;
|
|
8449
|
-
var ACCENT = new
|
|
8450
|
-
var SEGMENT_AXIS = new
|
|
9353
|
+
var ACCENT = new THREE26.Color("#4da3ff");
|
|
9354
|
+
var SEGMENT_AXIS = new THREE26.Vector3(0, 1, 0);
|
|
8451
9355
|
var HEAD_CLEARANCE = 0.25;
|
|
8452
9356
|
var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
8453
9357
|
constructor(locomotionSystem) {
|
|
8454
|
-
this.group = new
|
|
9358
|
+
this.group = new THREE26.Group();
|
|
8455
9359
|
/** Holds the segment chain that draws the arc. */
|
|
8456
|
-
this.arc = new
|
|
9360
|
+
this.arc = new THREE26.Group();
|
|
8457
9361
|
/**
|
|
8458
9362
|
* Unit cylinder along +Y, reused by every segment.
|
|
8459
9363
|
*
|
|
@@ -8462,14 +9366,14 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8462
9366
|
* scaled cylinders gives real thickness while rebuilding no geometry: each
|
|
8463
9367
|
* frame only moves, rotates and scales meshes that already exist.
|
|
8464
9368
|
*/
|
|
8465
|
-
this.segmentGeometry = new
|
|
9369
|
+
this.segmentGeometry = new THREE26.CylinderGeometry(1, 1, 1, 6, 1);
|
|
8466
9370
|
this.segments = [];
|
|
8467
|
-
this.marker = new
|
|
9371
|
+
this.marker = new THREE26.Group();
|
|
8468
9372
|
this.attached = false;
|
|
8469
|
-
this.scratchDirection = new
|
|
8470
|
-
this.scratchHead = new
|
|
8471
|
-
this.validColor = new
|
|
8472
|
-
this.invalidColor = new
|
|
9373
|
+
this.scratchDirection = new THREE26.Vector3();
|
|
9374
|
+
this.scratchHead = new THREE26.Vector3();
|
|
9375
|
+
this.validColor = new THREE26.Color();
|
|
9376
|
+
this.invalidColor = new THREE26.Color();
|
|
8473
9377
|
this.locomotionSystem = locomotionSystem;
|
|
8474
9378
|
this.group.name = "XRTeleportVisuals";
|
|
8475
9379
|
this.group.userData.ecsPreviewHidden = true;
|
|
@@ -8527,8 +9431,8 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8527
9431
|
const from = curve[i];
|
|
8528
9432
|
const to = curve[i + 1];
|
|
8529
9433
|
this.scratchDirection.subVectors(to, from);
|
|
8530
|
-
const
|
|
8531
|
-
if (
|
|
9434
|
+
const length2 = this.scratchDirection.length();
|
|
9435
|
+
if (length2 < 1e-6) {
|
|
8532
9436
|
segment.visible = false;
|
|
8533
9437
|
continue;
|
|
8534
9438
|
}
|
|
@@ -8536,9 +9440,9 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8536
9440
|
segment.position.copy(from).addScaledVector(this.scratchDirection, 0.5);
|
|
8537
9441
|
segment.quaternion.setFromUnitVectors(
|
|
8538
9442
|
SEGMENT_AXIS,
|
|
8539
|
-
this.scratchDirection.divideScalar(
|
|
9443
|
+
this.scratchDirection.divideScalar(length2)
|
|
8540
9444
|
);
|
|
8541
|
-
segment.scale.set(radius,
|
|
9445
|
+
segment.scale.set(radius, length2, radius);
|
|
8542
9446
|
const t = needed > 1 ? i / (needed - 1) : 0;
|
|
8543
9447
|
const fade = 1 - t * 0.75;
|
|
8544
9448
|
segment.material.color.copy(tint).multiplyScalar(fade);
|
|
@@ -8547,12 +9451,12 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8547
9451
|
/** Grow the segment pool to cover the current arc. */
|
|
8548
9452
|
ensureSegments(count) {
|
|
8549
9453
|
while (this.segments.length < count) {
|
|
8550
|
-
const material = new
|
|
9454
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
8551
9455
|
transparent: true,
|
|
8552
9456
|
depthTest: false,
|
|
8553
9457
|
depthWrite: false
|
|
8554
9458
|
});
|
|
8555
|
-
const mesh = new
|
|
9459
|
+
const mesh = new THREE26.Mesh(this.segmentGeometry, material);
|
|
8556
9460
|
mesh.frustumCulled = false;
|
|
8557
9461
|
mesh.renderOrder = 998;
|
|
8558
9462
|
mesh.raycast = () => {
|
|
@@ -8576,33 +9480,33 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8576
9480
|
return world.getComponent(entityId, XRRigComponent) ?? null;
|
|
8577
9481
|
}
|
|
8578
9482
|
createRing() {
|
|
8579
|
-
const geometry = new
|
|
9483
|
+
const geometry = new THREE26.RingGeometry(
|
|
8580
9484
|
MARKER_RADIUS * 0.72,
|
|
8581
9485
|
MARKER_RADIUS,
|
|
8582
9486
|
48
|
|
8583
9487
|
);
|
|
8584
9488
|
geometry.rotateX(-Math.PI / 2);
|
|
8585
|
-
return new
|
|
9489
|
+
return new THREE26.Mesh(
|
|
8586
9490
|
geometry,
|
|
8587
|
-
new
|
|
9491
|
+
new THREE26.MeshBasicMaterial({
|
|
8588
9492
|
color: ACCENT,
|
|
8589
9493
|
transparent: true,
|
|
8590
9494
|
opacity: 0.9,
|
|
8591
|
-
side:
|
|
9495
|
+
side: THREE26.DoubleSide,
|
|
8592
9496
|
depthTest: false
|
|
8593
9497
|
})
|
|
8594
9498
|
);
|
|
8595
9499
|
}
|
|
8596
9500
|
createDot() {
|
|
8597
|
-
const geometry = new
|
|
9501
|
+
const geometry = new THREE26.CircleGeometry(MARKER_RADIUS * 0.16, 24);
|
|
8598
9502
|
geometry.rotateX(-Math.PI / 2);
|
|
8599
|
-
return new
|
|
9503
|
+
return new THREE26.Mesh(
|
|
8600
9504
|
geometry,
|
|
8601
|
-
new
|
|
9505
|
+
new THREE26.MeshBasicMaterial({
|
|
8602
9506
|
color: ACCENT,
|
|
8603
9507
|
transparent: true,
|
|
8604
9508
|
opacity: 0.55,
|
|
8605
|
-
side:
|
|
9509
|
+
side: THREE26.DoubleSide,
|
|
8606
9510
|
depthTest: false
|
|
8607
9511
|
})
|
|
8608
9512
|
);
|
|
@@ -8713,7 +9617,7 @@ function boneDirections(joints, finger) {
|
|
|
8713
9617
|
const from = joints[chain[i - 1]];
|
|
8714
9618
|
const to = joints[chain[i]];
|
|
8715
9619
|
if (!from || !to) return null;
|
|
8716
|
-
const direction = new
|
|
9620
|
+
const direction = new THREE26.Vector3().subVectors(to, from);
|
|
8717
9621
|
if (direction.lengthSq() < 1e-12) return null;
|
|
8718
9622
|
directions.push(direction.normalize());
|
|
8719
9623
|
}
|
|
@@ -8786,8 +9690,8 @@ function computeSpread(joints, a, b) {
|
|
|
8786
9690
|
const bBase = joints[METACARPAL_JOINTS[b]];
|
|
8787
9691
|
const bTip = joints[TIP_JOINTS[b]];
|
|
8788
9692
|
if (!aBase || !aTip || !bBase || !bTip) return null;
|
|
8789
|
-
const dirA = new
|
|
8790
|
-
const dirB = new
|
|
9693
|
+
const dirA = new THREE26.Vector3().subVectors(aTip, aBase);
|
|
9694
|
+
const dirB = new THREE26.Vector3().subVectors(bTip, bBase);
|
|
8791
9695
|
if (dirA.lengthSq() < 1e-12 || dirB.lengthSq() < 1e-12) return null;
|
|
8792
9696
|
return clamp01((1 - dirA.normalize().dot(dirB.normalize())) / 0.45);
|
|
8793
9697
|
}
|
|
@@ -8797,18 +9701,18 @@ function computePalmPose(joints, handedness) {
|
|
|
8797
9701
|
const indexBase = joints["index-finger-metacarpal"];
|
|
8798
9702
|
const pinkyBase = joints["pinky-finger-metacarpal"];
|
|
8799
9703
|
if (!wrist || !indexBase || !pinkyBase) return null;
|
|
8800
|
-
const u = new
|
|
8801
|
-
const v = new
|
|
8802
|
-
const normal = new
|
|
9704
|
+
const u = new THREE26.Vector3().subVectors(indexBase, wrist);
|
|
9705
|
+
const v = new THREE26.Vector3().subVectors(pinkyBase, wrist);
|
|
9706
|
+
const normal = new THREE26.Vector3().crossVectors(u, v);
|
|
8803
9707
|
if (normal.lengthSq() < 1e-12) return null;
|
|
8804
9708
|
normal.normalize();
|
|
8805
9709
|
if (handedness === "left") normal.multiplyScalar(-1);
|
|
8806
|
-
const right = new
|
|
9710
|
+
const right = new THREE26.Vector3().subVectors(indexBase, pinkyBase);
|
|
8807
9711
|
if (right.lengthSq() < 1e-12) return null;
|
|
8808
9712
|
right.normalize();
|
|
8809
9713
|
if (handedness === "left") right.multiplyScalar(-1);
|
|
8810
|
-
const up = new
|
|
8811
|
-
const center = new
|
|
9714
|
+
const up = new THREE26.Vector3().crossVectors(normal, right).normalize();
|
|
9715
|
+
const center = new THREE26.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
|
|
8812
9716
|
return {
|
|
8813
9717
|
center,
|
|
8814
9718
|
normal,
|
|
@@ -8820,17 +9724,17 @@ function computePalmPose(joints, handedness) {
|
|
|
8820
9724
|
__name(computePalmPose, "computePalmPose");
|
|
8821
9725
|
function computeHandShape(joints, handedness) {
|
|
8822
9726
|
const fingers = {};
|
|
8823
|
-
let
|
|
9727
|
+
let tracked2 = 0;
|
|
8824
9728
|
for (const finger of XR_FINGERS) {
|
|
8825
9729
|
const curl = computeFingerCurl(joints, finger);
|
|
8826
9730
|
if (curl) {
|
|
8827
9731
|
fingers[finger] = curl;
|
|
8828
|
-
|
|
9732
|
+
tracked2 += 1;
|
|
8829
9733
|
} else {
|
|
8830
9734
|
fingers[finger] = { baseCurl: 0, tipCurl: 0, curl: 0 };
|
|
8831
9735
|
}
|
|
8832
9736
|
}
|
|
8833
|
-
if (
|
|
9737
|
+
if (tracked2 === 0) return null;
|
|
8834
9738
|
const pinch = {};
|
|
8835
9739
|
for (const finger of PINCH_FINGERS) {
|
|
8836
9740
|
pinch[finger] = computePinch(joints, finger) ?? 0;
|
|
@@ -8839,7 +9743,7 @@ function computeHandShape(joints, handedness) {
|
|
|
8839
9743
|
const thumbTip = joints["thumb-tip"];
|
|
8840
9744
|
let thumbDirection = null;
|
|
8841
9745
|
if (thumbBase && thumbTip) {
|
|
8842
|
-
const direction = new
|
|
9746
|
+
const direction = new THREE26.Vector3().subVectors(thumbTip, thumbBase);
|
|
8843
9747
|
if (direction.lengthSq() > 1e-12) thumbDirection = direction.normalize();
|
|
8844
9748
|
}
|
|
8845
9749
|
const fingerDirections = {};
|
|
@@ -8850,7 +9754,7 @@ function computeHandShape(joints, handedness) {
|
|
|
8850
9754
|
fingerDirections[finger] = null;
|
|
8851
9755
|
continue;
|
|
8852
9756
|
}
|
|
8853
|
-
const direction = new
|
|
9757
|
+
const direction = new THREE26.Vector3().subVectors(tip, base);
|
|
8854
9758
|
fingerDirections[finger] = direction.lengthSq() > 1e-12 ? direction.normalize() : null;
|
|
8855
9759
|
}
|
|
8856
9760
|
return {
|
|
@@ -8884,12 +9788,12 @@ function scoreAgainst(actual, target, tolerance) {
|
|
|
8884
9788
|
__name(scoreAgainst, "scoreAgainst");
|
|
8885
9789
|
var DEFAULT_DIRECTION_TOLERANCE = 45;
|
|
8886
9790
|
var WORLD_DIRECTIONS = {
|
|
8887
|
-
up: new
|
|
8888
|
-
down: new
|
|
8889
|
-
forward: new
|
|
8890
|
-
back: new
|
|
8891
|
-
left: new
|
|
8892
|
-
right: new
|
|
9791
|
+
up: new THREE26.Vector3(0, 1, 0),
|
|
9792
|
+
down: new THREE26.Vector3(0, -1, 0),
|
|
9793
|
+
forward: new THREE26.Vector3(0, 0, -1),
|
|
9794
|
+
back: new THREE26.Vector3(0, 0, 1),
|
|
9795
|
+
left: new THREE26.Vector3(-1, 0, 0),
|
|
9796
|
+
right: new THREE26.Vector3(1, 0, 0)
|
|
8893
9797
|
};
|
|
8894
9798
|
function axisVector(shape, axis) {
|
|
8895
9799
|
if (axis === "thumb") return shape.thumbDirection;
|
|
@@ -8904,7 +9808,7 @@ function resolveDirection(direction, shape, context) {
|
|
|
8904
9808
|
const head = context?.headPosition;
|
|
8905
9809
|
const origin = shape.palm?.center;
|
|
8906
9810
|
if (!head || !origin) return null;
|
|
8907
|
-
const toHead = new
|
|
9811
|
+
const toHead = new THREE26.Vector3().subVectors(head, origin);
|
|
8908
9812
|
if (toHead.lengthSq() < 1e-12) return null;
|
|
8909
9813
|
toHead.normalize();
|
|
8910
9814
|
return direction === "toward-head" ? toHead : toHead.multiplyScalar(-1);
|
|
@@ -8916,8 +9820,8 @@ function scoreDirections(actual, accepted, shape, toleranceDegrees, context) {
|
|
|
8916
9820
|
for (const direction of accepted) {
|
|
8917
9821
|
const wanted = resolveDirection(direction, shape, context);
|
|
8918
9822
|
if (!wanted) continue;
|
|
8919
|
-
const angle =
|
|
8920
|
-
Math.acos(
|
|
9823
|
+
const angle = THREE26.MathUtils.radToDeg(
|
|
9824
|
+
Math.acos(THREE26.MathUtils.clamp(actual.dot(wanted), -1, 1))
|
|
8921
9825
|
);
|
|
8922
9826
|
const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
|
|
8923
9827
|
const score = clamp01(1 - normalizedError / MATCH_FALLOFF);
|
|
@@ -8982,8 +9886,8 @@ function matchHandPose(shape, definition, context) {
|
|
|
8982
9886
|
if (!handAxis || !wanted) {
|
|
8983
9887
|
consider(0, "orientation");
|
|
8984
9888
|
} else {
|
|
8985
|
-
const angle =
|
|
8986
|
-
Math.acos(
|
|
9889
|
+
const angle = THREE26.MathUtils.radToDeg(
|
|
9890
|
+
Math.acos(THREE26.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
|
|
8987
9891
|
);
|
|
8988
9892
|
const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
|
|
8989
9893
|
consider(clamp01(1 - normalizedError / MATCH_FALLOFF), "orientation");
|
|
@@ -9061,7 +9965,7 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
|
|
|
9061
9965
|
this.trackers = /* @__PURE__ */ new Map();
|
|
9062
9966
|
this.shapes = /* @__PURE__ */ new Map();
|
|
9063
9967
|
/** Reused so head-relative orientation checks allocate nothing per frame. */
|
|
9064
|
-
this.headPosition = new
|
|
9968
|
+
this.headPosition = new THREE26.Vector3();
|
|
9065
9969
|
this.elapsed = 0;
|
|
9066
9970
|
this.warnedNoHands = false;
|
|
9067
9971
|
this.noHandSeconds = 0;
|
|
@@ -9077,8 +9981,8 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
|
|
|
9077
9981
|
const entries = this.collectEntries(world);
|
|
9078
9982
|
if (entries.length === 0) return;
|
|
9079
9983
|
if (!this.warnedNoHands) {
|
|
9080
|
-
const
|
|
9081
|
-
if (
|
|
9984
|
+
const tracked2 = this.shapes.get("left") !== null || this.shapes.get("right") !== null;
|
|
9985
|
+
if (tracked2) {
|
|
9082
9986
|
this.warnedNoHands = true;
|
|
9083
9987
|
} else {
|
|
9084
9988
|
this.noHandSeconds += deltaTime;
|
|
@@ -9224,6 +10128,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9224
10128
|
const interactable = world.getComponent(entityId, XRInteractableComponent);
|
|
9225
10129
|
if (!interactable?.enabled) continue;
|
|
9226
10130
|
if (interactable.hoverBehavior === "none") continue;
|
|
10131
|
+
if (isUiWidget(world, entityId)) continue;
|
|
9227
10132
|
this.begin(world, entityId, interactable);
|
|
9228
10133
|
}
|
|
9229
10134
|
for (const [entityId, record] of this.records) {
|
|
@@ -9244,7 +10149,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9244
10149
|
const wantsColor = interactable.hoverBehavior === "color" || interactable.hoverBehavior === "both";
|
|
9245
10150
|
this.records.set(entityId, {
|
|
9246
10151
|
shell: wantsColor ? this.addShell(world, entityId, interactable) : null,
|
|
9247
|
-
baseScale: new
|
|
10152
|
+
baseScale: new THREE26.Vector3(
|
|
9248
10153
|
transform.scale.x,
|
|
9249
10154
|
transform.scale.y,
|
|
9250
10155
|
transform.scale.z
|
|
@@ -9257,27 +10162,27 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9257
10162
|
addShell(world, entityId, interactable) {
|
|
9258
10163
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
9259
10164
|
if (!object) return null;
|
|
9260
|
-
const material = new
|
|
9261
|
-
color: new
|
|
10165
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
10166
|
+
color: new THREE26.Color(interactable.hoverColor),
|
|
9262
10167
|
// Back faces only, so the shell shows just outside the silhouette instead
|
|
9263
10168
|
// of covering the object.
|
|
9264
|
-
side:
|
|
10169
|
+
side: THREE26.BackSide,
|
|
9265
10170
|
transparent: true,
|
|
9266
10171
|
opacity: 0.85,
|
|
9267
10172
|
depthWrite: false
|
|
9268
10173
|
});
|
|
9269
|
-
const group = new
|
|
10174
|
+
const group = new THREE26.Group();
|
|
9270
10175
|
group.name = "XRHoverShell";
|
|
9271
10176
|
group.userData[XR_HOVER_SHELL_FLAG] = true;
|
|
9272
10177
|
group.renderOrder = 998;
|
|
9273
10178
|
object.traverse((child) => {
|
|
9274
|
-
if (!(child instanceof
|
|
10179
|
+
if (!(child instanceof THREE26.Mesh) || !child.geometry) return;
|
|
9275
10180
|
if (child.userData[XR_HOVER_SHELL_FLAG]) return;
|
|
9276
|
-
const clone = new
|
|
10181
|
+
const clone = new THREE26.Mesh(child.geometry, material);
|
|
9277
10182
|
child.updateWorldMatrix(true, false);
|
|
9278
10183
|
object.updateWorldMatrix(true, false);
|
|
9279
10184
|
clone.matrixAutoUpdate = false;
|
|
9280
|
-
clone.matrix.copy(object.matrixWorld).invert().multiply(child.matrixWorld).scale(new
|
|
10185
|
+
clone.matrix.copy(object.matrixWorld).invert().multiply(child.matrixWorld).scale(new THREE26.Vector3(SHELL_INFLATE, SHELL_INFLATE, SHELL_INFLATE));
|
|
9281
10186
|
clone.userData[XR_HOVER_SHELL_FLAG] = true;
|
|
9282
10187
|
clone.raycast = () => {
|
|
9283
10188
|
};
|
|
@@ -9326,7 +10231,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9326
10231
|
if (!shell) return;
|
|
9327
10232
|
shell.parent?.remove(shell);
|
|
9328
10233
|
shell.traverse((child) => {
|
|
9329
|
-
if (child instanceof
|
|
10234
|
+
if (child instanceof THREE26.Mesh) {
|
|
9330
10235
|
const material = child.material;
|
|
9331
10236
|
if (Array.isArray(material)) {
|
|
9332
10237
|
for (const entry of material) entry.dispose();
|
|
@@ -9352,5 +10257,5 @@ __name(_XRHoverVisualSystem, "XRHoverVisualSystem");
|
|
|
9352
10257
|
var XRHoverVisualSystem = _XRHoverVisualSystem;
|
|
9353
10258
|
|
|
9354
10259
|
export { ARC_GRAVITY, ARC_MAX_TIME, ARC_SPEED, ARC_STEPS, AnimationSystem, AudioMixer, AudioSystem, CURLED_COS, CameraSyncSystem, DEFAULT_DIRECTION_TOLERANCE, DEFAULT_ENTER_CONFIDENCE, DEFAULT_EXIT_CONFIDENCE, DEFAULT_LOST_GRACE_SECONDS, DEFAULT_MIN_HOLD_SECONDS, DEFAULT_SCRIPT_ERROR_RETRY_DELAY, EnvironmentSyncSystem, FALLBACK_HAND_SCALE, HandPoseTracker, IKSystem, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MATCH_FALLOFF, MAX_PLAUSIBLE_SPEED, MAX_SAMPLE_AGE_SECONDS, MaterialSyncSystem, MeshGeometrySystem, NO_XR_CAPABILITIES, ObjectVisibilitySystem, PINCH_FINGERS, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, SCRIPT_OBJECT_ROOT_FLAG, STRAIGHT_COS, ScriptBehaviourSystem, ScriptObject, ScriptObjectSystem, SlotChooser, TeleportAimGate, ThrowVelocityTracker, TransformSyncSystem, UIInteractionSystem, UIPanelSystem, VELOCITY_SAMPLES, VRTeleportAreaSystem, VideoSystem, XRAnchorSystem, XRControllerVisualSystem, XREnvironmentSystem, XRHandPoseSystem, XRHitTestSystem, XRHoverVisualSystem, XRInputSystem, XRInteractionSystem, XRLocomotionSystem, XRSessionSystem, XRTeleportVisualSystem, XR_FINGERS, XR_HOVER_SHELL_FLAG, angularVelocityFrom, applyHandMaterial, arcGroundCrossing, computeFingerCurl, computeHandShape, computePalmPose, computePalmWidth, computePinch, computeSpread, createHandMaterial, estimateHandScale, gripQuaternion, matchHandPose, readXrCapabilities, sampleTeleportArc, setWorldQuaternion, soundBankFiles, twoBoneIK };
|
|
9355
|
-
//# sourceMappingURL=chunk-
|
|
9356
|
-
//# sourceMappingURL=chunk-
|
|
10260
|
+
//# sourceMappingURL=chunk-TY3XCHOR.js.map
|
|
10261
|
+
//# sourceMappingURL=chunk-TY3XCHOR.js.map
|