@relu-interactives/spatial-ecs 0.8.0 → 0.9.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/{XRHandPose-G0Dl-F0w.d.ts → XRHandPose-CWSrsnYN.d.ts} +144 -1
- package/dist/{XRHandPose-VQMT1WXj.d.cts → XRHandPose-Dn2yiALk.d.cts} +144 -1
- 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-VYIWOXAY.js} +1377 -480
- package/dist/chunk-VYIWOXAY.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 +2 -2
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.js +1 -1
- 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 +1 -1
- package/dist/factories/index.d.ts +1 -1
- package/dist/factories/index.js +3 -3
- package/dist/{index-D9DjrUn3.d.cts → index-CAZHrh0q.d.cts} +5 -2
- package/dist/{index-DppafVu4.d.ts → index-CLtSMf2M.d.ts} +5 -2
- package/dist/{index-C61n65PE.d.ts → index-D5MmJNyj.d.ts} +26 -1
- package/dist/{index-C70N4BYG.d.cts → index-DiIjV2lm.d.cts} +26 -1
- package/dist/index.cjs +1787 -621
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +10 -10
- package/dist/network/index.cjs +177 -4
- package/dist/network/index.cjs.map +1 -1
- package/dist/network/index.js +3 -3
- package/dist/systems/index.cjs +1689 -523
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +1 -1
- package/dist/systems/index.d.ts +1 -1
- package/dist/systems/index.js +4 -4
- 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,96 @@ 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
|
+
image.src = URL.createObjectURL(typed);
|
|
7284
|
+
await image.decode();
|
|
7285
|
+
return image;
|
|
7286
|
+
})()
|
|
7287
|
+
).then((image) => {
|
|
7288
|
+
entry.value = image;
|
|
7289
|
+
}).catch((error) => {
|
|
7290
|
+
console.warn(`[spatial-ecs] Couldn't load UI image ${src}.`, error);
|
|
7291
|
+
}).finally(() => {
|
|
7292
|
+
entry.settled = true;
|
|
7293
|
+
});
|
|
7294
|
+
return null;
|
|
7295
|
+
}
|
|
7296
|
+
__name(uiImage, "uiImage");
|
|
7117
7297
|
|
|
7118
7298
|
// core/ui/uiCanvas.ts
|
|
7119
7299
|
var DEFAULT_PIXELS_PER_METER = 1024;
|
|
@@ -7186,18 +7366,21 @@ function clampLines(measure, lines, maxLines, maxWidthPx) {
|
|
|
7186
7366
|
}
|
|
7187
7367
|
__name(clampLines, "clampLines");
|
|
7188
7368
|
var UI_FONT_STACK = '-apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
7189
|
-
|
|
7190
|
-
|
|
7369
|
+
var NO_ASSETS = { image: /* @__PURE__ */ __name(() => null, "image") };
|
|
7370
|
+
function tracePath(ctx, x, y, w, h, radii) {
|
|
7371
|
+
const limit = Math.min(w / 2, h / 2);
|
|
7372
|
+
const fit = /* @__PURE__ */ __name((r) => Math.max(0, Math.min(r, limit)), "fit");
|
|
7373
|
+
const [tl, tr, br, bl] = (Array.isArray(radii) ? radii : [radii, radii, radii, radii]).map(fit);
|
|
7191
7374
|
ctx.beginPath();
|
|
7192
7375
|
if (typeof ctx.roundRect === "function") {
|
|
7193
|
-
ctx.roundRect(x, y, w, h,
|
|
7376
|
+
ctx.roundRect(x, y, w, h, [tl, tr, br, bl]);
|
|
7194
7377
|
return;
|
|
7195
7378
|
}
|
|
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,
|
|
7379
|
+
ctx.moveTo(x + tl, y);
|
|
7380
|
+
ctx.arcTo(x + w, y, x + w, y + h, tr);
|
|
7381
|
+
ctx.arcTo(x + w, y + h, x, y + h, br);
|
|
7382
|
+
ctx.arcTo(x, y + h, x, y, bl);
|
|
7383
|
+
ctx.arcTo(x, y, x + w, y, tl);
|
|
7201
7384
|
ctx.closePath();
|
|
7202
7385
|
}
|
|
7203
7386
|
__name(tracePath, "tracePath");
|
|
@@ -7217,108 +7400,244 @@ function withOpacity(ctx, color, opacity) {
|
|
|
7217
7400
|
return parsed;
|
|
7218
7401
|
}
|
|
7219
7402
|
__name(withOpacity, "withOpacity");
|
|
7220
|
-
function
|
|
7221
|
-
|
|
7222
|
-
const
|
|
7223
|
-
const
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7403
|
+
function fillStyleFor(ctx, paint, box, opacity) {
|
|
7404
|
+
if (paint.kind === "solid") return withOpacity(ctx, paint.color, opacity);
|
|
7405
|
+
const cx = box.x + box.w / 2;
|
|
7406
|
+
const cy = box.y + box.h / 2;
|
|
7407
|
+
let gradient;
|
|
7408
|
+
if (paint.kind === "linear") {
|
|
7409
|
+
const radians = paint.angle * Math.PI / 180;
|
|
7410
|
+
const dx = Math.sin(radians);
|
|
7411
|
+
const dy = -Math.cos(radians);
|
|
7412
|
+
const half = (Math.abs(box.w * dx) + Math.abs(box.h * dy)) / 2;
|
|
7413
|
+
gradient = ctx.createLinearGradient(
|
|
7414
|
+
cx - dx * half,
|
|
7415
|
+
cy - dy * half,
|
|
7416
|
+
cx + dx * half,
|
|
7417
|
+
cy + dy * half
|
|
7418
|
+
);
|
|
7419
|
+
} else {
|
|
7420
|
+
gradient = ctx.createRadialGradient(
|
|
7421
|
+
cx,
|
|
7422
|
+
cy,
|
|
7423
|
+
0,
|
|
7424
|
+
cx,
|
|
7425
|
+
cy,
|
|
7426
|
+
Math.max(box.w, box.h) / 2
|
|
7427
|
+
);
|
|
7428
|
+
}
|
|
7429
|
+
for (const stop of paint.stops) {
|
|
7430
|
+
gradient.addColorStop(stop.at, withOpacity(ctx, stop.color, opacity));
|
|
7431
|
+
}
|
|
7432
|
+
return gradient;
|
|
7433
|
+
}
|
|
7434
|
+
__name(fillStyleFor, "fillStyleFor");
|
|
7435
|
+
function drawImagePaint(ctx, paint, box, assets) {
|
|
7436
|
+
const image = assets.image(paint.src);
|
|
7437
|
+
if (!image) return;
|
|
7438
|
+
const sourceW = image.naturalWidth || box.w;
|
|
7439
|
+
const sourceH = image.naturalHeight || box.h;
|
|
7440
|
+
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);
|
|
7441
|
+
const w = paint.fit === "fill" ? box.w : sourceW * scale;
|
|
7442
|
+
const h = paint.fit === "fill" ? box.h : sourceH * scale;
|
|
7443
|
+
const x = box.x + (box.w - w) / 2;
|
|
7444
|
+
const y = box.y + (box.h - h) / 2;
|
|
7445
|
+
if (!paint.tint) {
|
|
7446
|
+
ctx.drawImage(image, x, y, w, h);
|
|
7447
|
+
return;
|
|
7448
|
+
}
|
|
7449
|
+
const scratch = assets.scratch?.(Math.ceil(w), Math.ceil(h));
|
|
7450
|
+
if (!scratch) {
|
|
7451
|
+
ctx.drawImage(image, x, y, w, h);
|
|
7452
|
+
return;
|
|
7453
|
+
}
|
|
7454
|
+
scratch.drawImage(image, 0, 0, w, h);
|
|
7455
|
+
scratch.globalCompositeOperation = "source-in";
|
|
7456
|
+
scratch.fillStyle = paint.tint;
|
|
7457
|
+
scratch.fillRect(0, 0, w, h);
|
|
7458
|
+
ctx.drawImage(scratch.canvas, x, y, w, h);
|
|
7459
|
+
}
|
|
7460
|
+
__name(drawImagePaint, "drawImagePaint");
|
|
7461
|
+
function pxRadii(radius, density) {
|
|
7462
|
+
return radius.map((r) => r * density);
|
|
7463
|
+
}
|
|
7464
|
+
__name(pxRadii, "pxRadii");
|
|
7465
|
+
function drawBoxShadow(ctx, box, radii, shadow, density) {
|
|
7466
|
+
ctx.save();
|
|
7467
|
+
ctx.shadowColor = shadow.color;
|
|
7468
|
+
ctx.shadowBlur = shadow.blur * density;
|
|
7469
|
+
ctx.shadowOffsetX = shadow.x * density;
|
|
7470
|
+
ctx.shadowOffsetY = -shadow.y * density;
|
|
7471
|
+
ctx.fillStyle = "#000000";
|
|
7472
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7230
7473
|
ctx.fill();
|
|
7231
|
-
|
|
7474
|
+
ctx.restore();
|
|
7475
|
+
ctx.save();
|
|
7476
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
7477
|
+
ctx.fillStyle = "#000000";
|
|
7478
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7479
|
+
ctx.fill();
|
|
7480
|
+
ctx.restore();
|
|
7481
|
+
}
|
|
7482
|
+
__name(drawBoxShadow, "drawBoxShadow");
|
|
7483
|
+
function drawChrome(ctx, box, density, chrome, assets = NO_ASSETS) {
|
|
7484
|
+
const radii = pxRadii(chrome.radius, density);
|
|
7485
|
+
for (const shadow of chrome.shadows) {
|
|
7486
|
+
drawBoxShadow(ctx, box, radii, shadow, density);
|
|
7487
|
+
}
|
|
7488
|
+
const opacity = Math.max(0, Math.min(1, chrome.fillOpacity));
|
|
7489
|
+
if (chrome.fill?.kind === "image") {
|
|
7490
|
+
ctx.save();
|
|
7491
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7492
|
+
ctx.clip();
|
|
7493
|
+
ctx.globalAlpha = opacity;
|
|
7494
|
+
drawImagePaint(ctx, chrome.fill, box, assets);
|
|
7495
|
+
ctx.restore();
|
|
7496
|
+
} else if (chrome.fill) {
|
|
7497
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7498
|
+
ctx.fillStyle = fillStyleFor(ctx, chrome.fill, box, opacity);
|
|
7499
|
+
ctx.fill();
|
|
7500
|
+
}
|
|
7501
|
+
if (chrome.edge) {
|
|
7502
|
+
const width = chrome.edge.width * density;
|
|
7503
|
+
ctx.save();
|
|
7504
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7505
|
+
ctx.clip();
|
|
7506
|
+
const fade = ctx.createLinearGradient(0, box.y, 0, box.y + box.h / 2);
|
|
7507
|
+
fade.addColorStop(0, chrome.edge.color);
|
|
7508
|
+
fade.addColorStop(1, withOpacity(ctx, chrome.edge.color, 0));
|
|
7509
|
+
ctx.strokeStyle = fade;
|
|
7510
|
+
ctx.lineWidth = width * 2;
|
|
7511
|
+
tracePath(ctx, box.x, box.y, box.w, box.h, radii);
|
|
7512
|
+
ctx.stroke();
|
|
7513
|
+
ctx.restore();
|
|
7514
|
+
}
|
|
7515
|
+
if (chrome.border) {
|
|
7516
|
+
const border = chrome.border.width * density;
|
|
7232
7517
|
tracePath(
|
|
7233
7518
|
ctx,
|
|
7234
|
-
border / 2,
|
|
7235
|
-
border / 2,
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
Math.max(0,
|
|
7519
|
+
box.x + border / 2,
|
|
7520
|
+
box.y + border / 2,
|
|
7521
|
+
box.w - border,
|
|
7522
|
+
box.h - border,
|
|
7523
|
+
radii.map((r) => Math.max(0, r - border / 2))
|
|
7239
7524
|
);
|
|
7240
|
-
ctx.strokeStyle =
|
|
7525
|
+
ctx.strokeStyle = chrome.border.color;
|
|
7241
7526
|
ctx.lineWidth = border;
|
|
7242
7527
|
ctx.stroke();
|
|
7243
7528
|
}
|
|
7244
7529
|
}
|
|
7245
7530
|
__name(drawChrome, "drawChrome");
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
const
|
|
7250
|
-
|
|
7531
|
+
var applyTransform2 = /* @__PURE__ */ __name((text, transform) => transform === "upper" ? text.toUpperCase() : transform === "lower" ? text.toLowerCase() : text, "applyTransform");
|
|
7532
|
+
function fillTracked(ctx, line, x, y, trackingPx, width) {
|
|
7533
|
+
let cursor = ctx.textAlign === "center" ? x - width / 2 : ctx.textAlign === "right" ? x - width : x;
|
|
7534
|
+
const align = ctx.textAlign;
|
|
7535
|
+
ctx.textAlign = "left";
|
|
7536
|
+
for (const glyph of line) {
|
|
7537
|
+
ctx.fillText(glyph, cursor, y);
|
|
7538
|
+
cursor += ctx.measureText(glyph).width + trackingPx;
|
|
7539
|
+
}
|
|
7540
|
+
ctx.textAlign = align;
|
|
7541
|
+
}
|
|
7542
|
+
__name(fillTracked, "fillTracked");
|
|
7543
|
+
function drawTextBlock(ctx, box, density, text, style, family = null, assets = NO_ASSETS) {
|
|
7544
|
+
const fontPx = Math.max(4, style.fontSize * density);
|
|
7545
|
+
const paddingPx = style.padding * density;
|
|
7546
|
+
const contentW = Math.max(1, box.w - paddingPx * 2);
|
|
7547
|
+
const contentH = Math.max(1, box.h - paddingPx * 2);
|
|
7251
7548
|
const lineHeightPx = fontPx * style.lineHeight;
|
|
7252
|
-
|
|
7253
|
-
const
|
|
7254
|
-
|
|
7549
|
+
const trackingPx = style.tracking * density;
|
|
7550
|
+
const stack = family ? `"${family}", ${UI_FONT_STACK}` : UI_FONT_STACK;
|
|
7551
|
+
ctx.font = `${style.fontWeight} ${fontPx}px ${stack}`;
|
|
7552
|
+
const nativeTracking = trackingPx !== 0 && "letterSpacing" in ctx;
|
|
7553
|
+
if (nativeTracking) {
|
|
7554
|
+
ctx.letterSpacing = `${trackingPx}px`;
|
|
7555
|
+
}
|
|
7556
|
+
const manualTracking = trackingPx !== 0 && !nativeTracking;
|
|
7557
|
+
const measure = /* @__PURE__ */ __name((s) => ctx.measureText(s).width + (manualTracking ? trackingPx * s.length : 0), "measure");
|
|
7558
|
+
const fits = Math.max(1, Math.floor(contentH / lineHeightPx));
|
|
7559
|
+
const maxLines = style.maxLines ? Math.min(fits, style.maxLines) : fits;
|
|
7255
7560
|
const lines = clampLines(
|
|
7256
7561
|
measure,
|
|
7257
|
-
wrapText(measure, text, contentW),
|
|
7562
|
+
wrapText(measure, applyTransform2(text, style.transform), contentW),
|
|
7258
7563
|
maxLines,
|
|
7259
7564
|
contentW
|
|
7260
7565
|
);
|
|
7261
7566
|
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" ?
|
|
7567
|
+
const top = style.valign === "top" ? box.y + paddingPx : style.valign === "bottom" ? box.y + box.h - paddingPx - blockH : box.y + (box.h - blockH) / 2;
|
|
7568
|
+
const anchorX = style.align === "left" ? box.x + paddingPx : style.align === "right" ? box.x + box.w - paddingPx : box.x + box.w / 2;
|
|
7264
7569
|
ctx.save();
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7570
|
+
if (style.paint.kind === "image") {
|
|
7571
|
+
ctx.fillStyle = "#ffffff";
|
|
7572
|
+
} else {
|
|
7573
|
+
ctx.fillStyle = fillStyleFor(ctx, style.paint, box, 1);
|
|
7574
|
+
}
|
|
7575
|
+
if (style.shadow) {
|
|
7576
|
+
ctx.shadowColor = style.shadow.color;
|
|
7577
|
+
ctx.shadowBlur = style.shadow.blur * density;
|
|
7578
|
+
ctx.shadowOffsetX = style.shadow.x * density;
|
|
7579
|
+
ctx.shadowOffsetY = -style.shadow.y * density;
|
|
7580
|
+
}
|
|
7268
7581
|
ctx.textAlign = style.align;
|
|
7269
7582
|
ctx.textBaseline = "middle";
|
|
7270
7583
|
for (let i = 0; i < lines.length; i += 1) {
|
|
7271
|
-
|
|
7584
|
+
const y = top + (i + 0.5) * lineHeightPx;
|
|
7585
|
+
if (manualTracking) {
|
|
7586
|
+
fillTracked(ctx, lines[i], anchorX, y, trackingPx, measure(lines[i]));
|
|
7587
|
+
} else {
|
|
7588
|
+
ctx.fillText(lines[i], anchorX, y);
|
|
7589
|
+
}
|
|
7272
7590
|
}
|
|
7273
7591
|
ctx.restore();
|
|
7592
|
+
if (style.paint.kind === "image") {
|
|
7593
|
+
ctx.save();
|
|
7594
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
7595
|
+
drawImagePaint(ctx, style.paint, box, assets);
|
|
7596
|
+
ctx.restore();
|
|
7597
|
+
}
|
|
7598
|
+
if (nativeTracking) {
|
|
7599
|
+
ctx.letterSpacing = "0px";
|
|
7600
|
+
}
|
|
7274
7601
|
}
|
|
7275
7602
|
__name(drawTextBlock, "drawTextBlock");
|
|
7276
|
-
function panelSignature(widthM, heightM, size,
|
|
7603
|
+
function panelSignature(widthM, heightM, size, chrome, loaded = null) {
|
|
7277
7604
|
return JSON.stringify([
|
|
7278
7605
|
widthM,
|
|
7279
7606
|
heightM,
|
|
7280
7607
|
size.pxWidth,
|
|
7281
7608
|
size.pxHeight,
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
style.cornerRadiusMeters,
|
|
7285
|
-
style.borderWidthMeters,
|
|
7286
|
-
style.borderColor
|
|
7609
|
+
chrome,
|
|
7610
|
+
loaded
|
|
7287
7611
|
]);
|
|
7288
7612
|
}
|
|
7289
7613
|
__name(panelSignature, "panelSignature");
|
|
7290
|
-
function textSignature(widthM, heightM, size, text, style) {
|
|
7614
|
+
function textSignature(widthM, heightM, size, text, style, family = null) {
|
|
7291
7615
|
return JSON.stringify([
|
|
7292
7616
|
widthM,
|
|
7293
7617
|
heightM,
|
|
7294
7618
|
size.pxWidth,
|
|
7295
7619
|
size.pxHeight,
|
|
7296
7620
|
text,
|
|
7297
|
-
style
|
|
7298
|
-
|
|
7299
|
-
style.color,
|
|
7300
|
-
style.align,
|
|
7301
|
-
style.valign,
|
|
7302
|
-
style.lineHeight,
|
|
7303
|
-
style.paddingMeters
|
|
7621
|
+
style,
|
|
7622
|
+
family
|
|
7304
7623
|
]);
|
|
7305
7624
|
}
|
|
7306
7625
|
__name(textSignature, "textSignature");
|
|
7307
|
-
function buttonSignature(widthM, heightM, size,
|
|
7626
|
+
function buttonSignature(widthM, heightM, size, chrome, label, text, family = null, loaded = null) {
|
|
7308
7627
|
return JSON.stringify([
|
|
7309
|
-
panelSignature(widthM, heightM, size,
|
|
7628
|
+
panelSignature(widthM, heightM, size, chrome, loaded),
|
|
7310
7629
|
label,
|
|
7311
|
-
text
|
|
7312
|
-
|
|
7313
|
-
text.color
|
|
7630
|
+
text,
|
|
7631
|
+
family
|
|
7314
7632
|
]);
|
|
7315
7633
|
}
|
|
7316
7634
|
__name(buttonSignature, "buttonSignature");
|
|
7317
|
-
function trackSignature(widthM, heightM, size,
|
|
7635
|
+
function trackSignature(widthM, heightM, size, chrome, accentColor, knobColor, variant = null) {
|
|
7318
7636
|
return JSON.stringify([
|
|
7319
|
-
panelSignature(widthM, heightM, size,
|
|
7637
|
+
panelSignature(widthM, heightM, size, chrome),
|
|
7320
7638
|
accentColor,
|
|
7321
|
-
knobColor
|
|
7639
|
+
knobColor,
|
|
7640
|
+
variant
|
|
7322
7641
|
]);
|
|
7323
7642
|
}
|
|
7324
7643
|
__name(trackSignature, "trackSignature");
|
|
@@ -7328,17 +7647,226 @@ function drawRoundedBar(ctx, pxX, pxY, pxW, pxH, color) {
|
|
|
7328
7647
|
ctx.fill();
|
|
7329
7648
|
}
|
|
7330
7649
|
__name(drawRoundedBar, "drawRoundedBar");
|
|
7650
|
+
function drawCheckMark(ctx, box, color) {
|
|
7651
|
+
ctx.beginPath();
|
|
7652
|
+
ctx.moveTo(box.x + box.w * 0.24, box.y + box.h * 0.54);
|
|
7653
|
+
ctx.lineTo(box.x + box.w * 0.43, box.y + box.h * 0.72);
|
|
7654
|
+
ctx.lineTo(box.x + box.w * 0.77, box.y + box.h * 0.3);
|
|
7655
|
+
ctx.strokeStyle = color;
|
|
7656
|
+
ctx.lineWidth = box.h * 0.13;
|
|
7657
|
+
ctx.lineCap = "round";
|
|
7658
|
+
ctx.lineJoin = "round";
|
|
7659
|
+
ctx.stroke();
|
|
7660
|
+
}
|
|
7661
|
+
__name(drawCheckMark, "drawCheckMark");
|
|
7662
|
+
function drawDot(ctx, cx, cy, radius, color) {
|
|
7663
|
+
ctx.beginPath();
|
|
7664
|
+
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
|
|
7665
|
+
ctx.fillStyle = color;
|
|
7666
|
+
ctx.fill();
|
|
7667
|
+
}
|
|
7668
|
+
__name(drawDot, "drawDot");
|
|
7669
|
+
function drawRing(ctx, box, t, trackColor, accentColor) {
|
|
7670
|
+
const thickness = Math.min(box.w, box.h) * 0.14;
|
|
7671
|
+
const radius = Math.min(box.w, box.h) / 2 - thickness / 2;
|
|
7672
|
+
const cx = box.x + box.w / 2;
|
|
7673
|
+
const cy = box.y + box.h / 2;
|
|
7674
|
+
ctx.lineWidth = thickness;
|
|
7675
|
+
ctx.lineCap = "round";
|
|
7676
|
+
ctx.beginPath();
|
|
7677
|
+
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
|
|
7678
|
+
ctx.strokeStyle = trackColor;
|
|
7679
|
+
ctx.stroke();
|
|
7680
|
+
if (t <= 0) return;
|
|
7681
|
+
const start = -Math.PI / 2;
|
|
7682
|
+
ctx.beginPath();
|
|
7683
|
+
ctx.arc(cx, cy, radius, start, start + t * Math.PI * 2);
|
|
7684
|
+
ctx.strokeStyle = accentColor;
|
|
7685
|
+
ctx.stroke();
|
|
7686
|
+
}
|
|
7687
|
+
__name(drawRing, "drawRing");
|
|
7688
|
+
function drawIconLabel(ctx, box, density, label, style, family, icon, position, assets) {
|
|
7689
|
+
const fontPx = style.fontSize * density;
|
|
7690
|
+
const iconPx = fontPx * 1.3;
|
|
7691
|
+
const gapPx = label ? fontPx * 0.5 : 0;
|
|
7692
|
+
const stack = family ? `"${family}", ${UI_FONT_STACK}` : UI_FONT_STACK;
|
|
7693
|
+
ctx.font = `${style.fontWeight} ${fontPx}px ${stack}`;
|
|
7694
|
+
const labelPx = label ? ctx.measureText(label).width : 0;
|
|
7695
|
+
const groupPx = iconPx + gapPx + labelPx;
|
|
7696
|
+
const startX = box.x + (box.w - groupPx) / 2;
|
|
7697
|
+
const iconX = position === "left" ? startX : startX + labelPx + gapPx;
|
|
7698
|
+
const labelX = position === "left" ? startX + iconPx + gapPx : startX;
|
|
7699
|
+
drawImagePaint(
|
|
7700
|
+
ctx,
|
|
7701
|
+
{ src: icon, fit: "contain", tint: style.color },
|
|
7702
|
+
{ x: iconX, y: box.y + (box.h - iconPx) / 2, w: iconPx, h: iconPx },
|
|
7703
|
+
assets
|
|
7704
|
+
);
|
|
7705
|
+
if (label) {
|
|
7706
|
+
drawTextBlock(
|
|
7707
|
+
ctx,
|
|
7708
|
+
{ x: labelX, y: box.y, w: labelPx + 2, h: box.h },
|
|
7709
|
+
density,
|
|
7710
|
+
label,
|
|
7711
|
+
{ ...style, align: "left", padding: 0 },
|
|
7712
|
+
family,
|
|
7713
|
+
assets
|
|
7714
|
+
);
|
|
7715
|
+
}
|
|
7716
|
+
}
|
|
7717
|
+
__name(drawIconLabel, "drawIconLabel");
|
|
7718
|
+
|
|
7719
|
+
// core/ui/uiPaintOrder.ts
|
|
7720
|
+
var BASE_RENDER_ORDER = 10;
|
|
7721
|
+
var MAX_RENDER_ORDER = 890;
|
|
7722
|
+
var MAX_TREE_RANK = MAX_RENDER_ORDER - BASE_RENDER_ORDER - 1;
|
|
7723
|
+
var SLOT_STEP = 1e-4;
|
|
7724
|
+
var SLOTS_PER_WIDGET = 3;
|
|
7725
|
+
var MAX_WIDGET_INDEX = Math.floor(1 / SLOT_STEP / SLOTS_PER_WIDGET) - 1;
|
|
7726
|
+
var PLANE_EPSILON_METERS = 1e-3;
|
|
7727
|
+
var PARALLEL_DOT = 1 - 1e-4;
|
|
7728
|
+
var dot = /* @__PURE__ */ __name((a, b) => a.x * b.x + a.y * b.y + a.z * b.z, "dot");
|
|
7729
|
+
var length = /* @__PURE__ */ __name((a) => Math.sqrt(dot(a, a)), "length");
|
|
7730
|
+
var subtract = /* @__PURE__ */ __name((a, b) => ({
|
|
7731
|
+
x: a.x - b.x,
|
|
7732
|
+
y: a.y - b.y,
|
|
7733
|
+
z: a.z - b.z
|
|
7734
|
+
}), "subtract");
|
|
7735
|
+
function unit(a) {
|
|
7736
|
+
const len = length(a);
|
|
7737
|
+
if (len < 1e-9) return { x: 0, y: 0, z: 0 };
|
|
7738
|
+
return { x: a.x / len, y: a.y / len, z: a.z / len };
|
|
7739
|
+
}
|
|
7740
|
+
__name(unit, "unit");
|
|
7741
|
+
function normalOf(rect) {
|
|
7742
|
+
const { halfX: a, halfY: b } = rect;
|
|
7743
|
+
return unit({
|
|
7744
|
+
x: a.y * b.z - a.z * b.y,
|
|
7745
|
+
y: a.z * b.x - a.x * b.z,
|
|
7746
|
+
z: a.x * b.y - a.y * b.x
|
|
7747
|
+
});
|
|
7748
|
+
}
|
|
7749
|
+
__name(normalOf, "normalOf");
|
|
7750
|
+
var planeDistance = /* @__PURE__ */ __name((rect, normal, eye) => Math.abs(dot(subtract(eye, rect.center), normal)), "planeDistance");
|
|
7751
|
+
function closestPointDistance(rect, eye) {
|
|
7752
|
+
const toEye = subtract(eye, rect.center);
|
|
7753
|
+
const lenX = length(rect.halfX);
|
|
7754
|
+
const lenY = length(rect.halfY);
|
|
7755
|
+
const axisX = unit(rect.halfX);
|
|
7756
|
+
const axisY = unit(rect.halfY);
|
|
7757
|
+
const s = Math.max(-lenX, Math.min(lenX, dot(toEye, axisX)));
|
|
7758
|
+
const t = Math.max(-lenY, Math.min(lenY, dot(toEye, axisY)));
|
|
7759
|
+
return length({
|
|
7760
|
+
x: toEye.x - axisX.x * s - axisY.x * t,
|
|
7761
|
+
y: toEye.y - axisX.y * s - axisY.y * t,
|
|
7762
|
+
z: toEye.z - axisX.z * s - axisY.z * t
|
|
7763
|
+
});
|
|
7764
|
+
}
|
|
7765
|
+
__name(closestPointDistance, "closestPointDistance");
|
|
7766
|
+
var areaOf = /* @__PURE__ */ __name((rect) => length(rect.halfX) * length(rect.halfY), "areaOf");
|
|
7767
|
+
function comparePaintRects(a, b, eye) {
|
|
7768
|
+
const normalA = normalOf(a);
|
|
7769
|
+
const normalB = normalOf(b);
|
|
7770
|
+
const parallel = Math.abs(dot(normalA, normalB)) >= PARALLEL_DOT;
|
|
7771
|
+
const distanceA = parallel ? planeDistance(a, normalA, eye) : closestPointDistance(a, eye);
|
|
7772
|
+
const distanceB = parallel ? planeDistance(b, normalB, eye) : closestPointDistance(b, eye);
|
|
7773
|
+
if (Math.abs(distanceA - distanceB) > PLANE_EPSILON_METERS) {
|
|
7774
|
+
return distanceB - distanceA;
|
|
7775
|
+
}
|
|
7776
|
+
const areaA = areaOf(a);
|
|
7777
|
+
const areaB = areaOf(b);
|
|
7778
|
+
if (areaA !== areaB) return areaB - areaA;
|
|
7779
|
+
return a.id - b.id;
|
|
7780
|
+
}
|
|
7781
|
+
__name(comparePaintRects, "comparePaintRects");
|
|
7782
|
+
function buildPaintTrees(nodes) {
|
|
7783
|
+
const known = new Set(nodes.map((node) => node.id));
|
|
7784
|
+
const children = /* @__PURE__ */ new Map();
|
|
7785
|
+
const roots = [];
|
|
7786
|
+
for (const node of nodes) {
|
|
7787
|
+
if (node.parent !== null && known.has(node.parent)) {
|
|
7788
|
+
const siblings = children.get(node.parent);
|
|
7789
|
+
if (siblings) siblings.push(node.id);
|
|
7790
|
+
else children.set(node.parent, [node.id]);
|
|
7791
|
+
} else {
|
|
7792
|
+
roots.push(node.id);
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
const trees = [];
|
|
7796
|
+
const visited = /* @__PURE__ */ new Set();
|
|
7797
|
+
const walk = /* @__PURE__ */ __name((id, order) => {
|
|
7798
|
+
if (visited.has(id)) return;
|
|
7799
|
+
visited.add(id);
|
|
7800
|
+
order.push(id);
|
|
7801
|
+
const kids = children.get(id);
|
|
7802
|
+
if (!kids) return;
|
|
7803
|
+
for (const kid of [...kids].sort((a, b) => a - b)) walk(kid, order);
|
|
7804
|
+
}, "walk");
|
|
7805
|
+
for (const rootId of [...roots].sort((a, b) => a - b)) {
|
|
7806
|
+
const order = [];
|
|
7807
|
+
walk(rootId, order);
|
|
7808
|
+
trees.push({ rootId, order });
|
|
7809
|
+
}
|
|
7810
|
+
return trees;
|
|
7811
|
+
}
|
|
7812
|
+
__name(buildPaintTrees, "buildPaintTrees");
|
|
7813
|
+
function paintSlots(treeRank, widgetIndex) {
|
|
7814
|
+
const base = BASE_RENDER_ORDER + Math.min(treeRank, MAX_TREE_RANK);
|
|
7815
|
+
const index = Math.min(widgetIndex, MAX_WIDGET_INDEX);
|
|
7816
|
+
const slot = /* @__PURE__ */ __name((offset) => base + (index * SLOTS_PER_WIDGET + offset) * SLOT_STEP, "slot");
|
|
7817
|
+
return { face: slot(0), parts: slot(1), descendants: slot(2) };
|
|
7818
|
+
}
|
|
7819
|
+
__name(paintSlots, "paintSlots");
|
|
7820
|
+
function assignPaintOrder(trees, rects, eye) {
|
|
7821
|
+
const sorted = trees.filter((tree) => rects.has(tree.rootId)).sort(
|
|
7822
|
+
(a, b) => comparePaintRects(
|
|
7823
|
+
rects.get(a.rootId),
|
|
7824
|
+
rects.get(b.rootId),
|
|
7825
|
+
eye
|
|
7826
|
+
)
|
|
7827
|
+
);
|
|
7828
|
+
const slots = /* @__PURE__ */ new Map();
|
|
7829
|
+
sorted.forEach((tree, rank) => {
|
|
7830
|
+
tree.order.forEach((id, index) => {
|
|
7831
|
+
slots.set(id, paintSlots(rank, index));
|
|
7832
|
+
});
|
|
7833
|
+
});
|
|
7834
|
+
return slots;
|
|
7835
|
+
}
|
|
7836
|
+
__name(assignPaintOrder, "assignPaintOrder");
|
|
7331
7837
|
|
|
7332
7838
|
// core/systems/UIPanelSystem.ts
|
|
7333
|
-
var FACE_RENDER_ORDER = 10;
|
|
7334
7839
|
var CHILD_Z = 2e-3;
|
|
7840
|
+
var DESCENDANT_WALK_INTERVAL = 30;
|
|
7841
|
+
var METER_STEPS = 200;
|
|
7842
|
+
var CLEAR_CHROME = {
|
|
7843
|
+
backgroundColor: "#000000",
|
|
7844
|
+
backgroundOpacity: 0,
|
|
7845
|
+
cornerRadius: 0,
|
|
7846
|
+
borderWidth: 0,
|
|
7847
|
+
borderColor: "#000000"
|
|
7848
|
+
};
|
|
7849
|
+
var PAINT_STAMP_KEY = "__uiPaintStamp";
|
|
7335
7850
|
var _UIPanelSystem = class _UIPanelSystem {
|
|
7336
7851
|
constructor(options) {
|
|
7337
7852
|
this.entries = /* @__PURE__ */ new Map();
|
|
7853
|
+
this.framesUntilDescendantWalk = 0;
|
|
7854
|
+
/** Whether any panel defines tokens, so plain scenes skip the parent walk. */
|
|
7855
|
+
this.anyTokens = false;
|
|
7856
|
+
this.drawAssets = {
|
|
7857
|
+
image: /* @__PURE__ */ __name((src) => uiImage(src), "image"),
|
|
7858
|
+
scratch: /* @__PURE__ */ __name((width, height) => {
|
|
7859
|
+
const canvas = this.createCanvas();
|
|
7860
|
+
canvas.width = width;
|
|
7861
|
+
canvas.height = height;
|
|
7862
|
+
return canvas.getContext("2d");
|
|
7863
|
+
}, "scratch")
|
|
7864
|
+
};
|
|
7338
7865
|
this.createCanvas = options?.createCanvas ?? (() => document.createElement("canvas"));
|
|
7339
7866
|
}
|
|
7340
7867
|
update(world, deltaTime = 0) {
|
|
7341
7868
|
const live = /* @__PURE__ */ new Set();
|
|
7869
|
+
this.anyTokens = world.query(UIPanelComponent).some((id) => world.getComponent(id, UIPanelComponent)?.tokens);
|
|
7342
7870
|
for (const entityId of world.query(UIPanelComponent, Object3DRef)) {
|
|
7343
7871
|
const panel = world.getComponent(entityId, UIPanelComponent);
|
|
7344
7872
|
if (!panel) continue;
|
|
@@ -7376,6 +7904,7 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7376
7904
|
this.entries.delete(entityId);
|
|
7377
7905
|
}
|
|
7378
7906
|
}
|
|
7907
|
+
this.applyPaintOrder(world);
|
|
7379
7908
|
}
|
|
7380
7909
|
/** All GPU/canvas resources; call on world teardown. */
|
|
7381
7910
|
dispose() {
|
|
@@ -7384,84 +7913,188 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7384
7913
|
}
|
|
7385
7914
|
// ── Widgets ────────────────────────────────────────────────────────────────
|
|
7386
7915
|
syncPanel(world, entityId, panel) {
|
|
7387
|
-
const
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7916
|
+
const chrome = resolveChrome(
|
|
7917
|
+
panel,
|
|
7918
|
+
panel.style,
|
|
7919
|
+
this.tokensFor(world, entityId)
|
|
7920
|
+
);
|
|
7921
|
+
const bleed = chromeBleed(chrome);
|
|
7922
|
+
const size = resolveCanvasSize(
|
|
7923
|
+
panel.width + bleed * 2,
|
|
7924
|
+
panel.height + bleed * 2,
|
|
7925
|
+
panel.pixelDensity
|
|
7926
|
+
);
|
|
7927
|
+
const signature = panelSignature(
|
|
7928
|
+
panel.width,
|
|
7929
|
+
panel.height,
|
|
7930
|
+
size,
|
|
7931
|
+
chrome,
|
|
7932
|
+
imagesLoaded(chrome)
|
|
7933
|
+
);
|
|
7934
|
+
this.rebuildIfChanged(
|
|
7935
|
+
world,
|
|
7936
|
+
entityId,
|
|
7937
|
+
signature,
|
|
7938
|
+
panel,
|
|
7939
|
+
bleed,
|
|
7940
|
+
size,
|
|
7941
|
+
(ctx) => {
|
|
7942
|
+
drawChrome(
|
|
7943
|
+
ctx,
|
|
7944
|
+
layoutBox(panel, bleed, size.density),
|
|
7945
|
+
size.density,
|
|
7946
|
+
chrome,
|
|
7947
|
+
this.drawAssets
|
|
7948
|
+
);
|
|
7949
|
+
},
|
|
7950
|
+
THREE26.DoubleSide
|
|
7951
|
+
);
|
|
7399
7952
|
}
|
|
7400
7953
|
syncText(world, entityId, text) {
|
|
7401
|
-
const
|
|
7402
|
-
const
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
const signature =
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7954
|
+
const tokens = this.tokensFor(world, entityId);
|
|
7955
|
+
const chrome = text.style ? resolveChrome(CLEAR_CHROME, text.style, tokens) : null;
|
|
7956
|
+
const bleed = chrome ? chromeBleed(chrome) : 0;
|
|
7957
|
+
const size = resolveCanvasSize(
|
|
7958
|
+
text.width + bleed * 2,
|
|
7959
|
+
text.height + bleed * 2,
|
|
7960
|
+
text.pixelDensity
|
|
7961
|
+
);
|
|
7962
|
+
const style = resolveText(text, text.style, tokens);
|
|
7963
|
+
const family = familyOf(style.font);
|
|
7964
|
+
const signature = JSON.stringify([
|
|
7965
|
+
textSignature(text.width, text.height, size, text.text, style, family),
|
|
7966
|
+
chrome,
|
|
7967
|
+
chrome ? imagesLoaded(chrome) : null
|
|
7968
|
+
]);
|
|
7969
|
+
this.rebuildIfChanged(
|
|
7970
|
+
world,
|
|
7971
|
+
entityId,
|
|
7972
|
+
signature,
|
|
7973
|
+
text,
|
|
7974
|
+
bleed,
|
|
7975
|
+
size,
|
|
7976
|
+
(ctx) => {
|
|
7977
|
+
const box = layoutBox(text, bleed, size.density);
|
|
7978
|
+
if (chrome) {
|
|
7979
|
+
drawChrome(ctx, box, size.density, chrome, this.drawAssets);
|
|
7980
|
+
}
|
|
7981
|
+
drawTextBlock(
|
|
7982
|
+
ctx,
|
|
7983
|
+
box,
|
|
7984
|
+
size.density,
|
|
7985
|
+
text.text,
|
|
7986
|
+
style,
|
|
7987
|
+
family,
|
|
7988
|
+
this.drawAssets
|
|
7989
|
+
);
|
|
7990
|
+
}
|
|
7991
|
+
);
|
|
7416
7992
|
}
|
|
7417
7993
|
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
|
-
|
|
7994
|
+
const tokens = this.tokensFor(world, entityId);
|
|
7995
|
+
const chrome = resolveChrome(button, button.style, tokens);
|
|
7996
|
+
const bleed = chromeBleed(chrome);
|
|
7997
|
+
const size = resolveCanvasSize(
|
|
7998
|
+
button.width + bleed * 2,
|
|
7999
|
+
button.height + bleed * 2,
|
|
8000
|
+
button.pixelDensity
|
|
8001
|
+
);
|
|
8002
|
+
const label = resolveText(
|
|
8003
|
+
{
|
|
8004
|
+
fontSize: button.fontSize,
|
|
8005
|
+
fontWeight: button.fontWeight,
|
|
8006
|
+
color: button.textColor,
|
|
8007
|
+
align: "center",
|
|
8008
|
+
valign: "middle",
|
|
8009
|
+
lineHeight: 1.2,
|
|
8010
|
+
padding: 0.01
|
|
8011
|
+
},
|
|
8012
|
+
button.style,
|
|
8013
|
+
tokens
|
|
8014
|
+
);
|
|
8015
|
+
const family = familyOf(label.font);
|
|
8016
|
+
const icon = button.icon ? resolveToken(button.icon, tokens) : null;
|
|
7435
8017
|
const signature = buttonSignature(
|
|
7436
8018
|
button.width,
|
|
7437
8019
|
button.height,
|
|
7438
8020
|
size,
|
|
7439
8021
|
chrome,
|
|
7440
8022
|
button.label,
|
|
7441
|
-
label
|
|
8023
|
+
label,
|
|
8024
|
+
family,
|
|
8025
|
+
[imagesLoaded(chrome), icon, icon ? !!uiImage(icon) : false]
|
|
8026
|
+
);
|
|
8027
|
+
this.rebuildIfChanged(
|
|
8028
|
+
world,
|
|
8029
|
+
entityId,
|
|
8030
|
+
signature,
|
|
8031
|
+
button,
|
|
8032
|
+
bleed,
|
|
8033
|
+
size,
|
|
8034
|
+
(ctx) => {
|
|
8035
|
+
const box = layoutBox(button, bleed, size.density);
|
|
8036
|
+
drawChrome(ctx, box, size.density, chrome, this.drawAssets);
|
|
8037
|
+
if (icon) {
|
|
8038
|
+
drawIconLabel(
|
|
8039
|
+
ctx,
|
|
8040
|
+
box,
|
|
8041
|
+
size.density,
|
|
8042
|
+
button.label,
|
|
8043
|
+
label,
|
|
8044
|
+
family,
|
|
8045
|
+
icon,
|
|
8046
|
+
button.iconPosition ?? "left",
|
|
8047
|
+
this.drawAssets
|
|
8048
|
+
);
|
|
8049
|
+
} else {
|
|
8050
|
+
drawTextBlock(
|
|
8051
|
+
ctx,
|
|
8052
|
+
box,
|
|
8053
|
+
size.density,
|
|
8054
|
+
button.label,
|
|
8055
|
+
label,
|
|
8056
|
+
family,
|
|
8057
|
+
this.drawAssets
|
|
8058
|
+
);
|
|
8059
|
+
}
|
|
8060
|
+
}
|
|
7442
8061
|
);
|
|
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
8062
|
}
|
|
7448
8063
|
syncToggle(world, entityId, toggle, deltaTime) {
|
|
7449
|
-
const
|
|
7450
|
-
const
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
8064
|
+
const tokens = this.tokensFor(world, entityId);
|
|
8065
|
+
const accent = resolveToken(toggle.accentColor, tokens);
|
|
8066
|
+
const track = resolveToken(toggle.trackColor, tokens);
|
|
8067
|
+
const knobColor = resolveToken(toggle.knobColor, tokens);
|
|
8068
|
+
const size = resolveCanvasSize(
|
|
8069
|
+
toggle.width,
|
|
8070
|
+
toggle.height,
|
|
8071
|
+
toggle.pixelDensity
|
|
8072
|
+
);
|
|
8073
|
+
const variant = toggle.variant ?? "switch";
|
|
8074
|
+
if (variant !== "switch") {
|
|
8075
|
+
this.syncMarkToggle(world, entityId, toggle, accent, track, knobColor);
|
|
8076
|
+
return;
|
|
8077
|
+
}
|
|
8078
|
+
const chrome = resolveChrome(
|
|
8079
|
+
{
|
|
8080
|
+
backgroundColor: toggle.value ? accent : track,
|
|
8081
|
+
backgroundOpacity: 1,
|
|
8082
|
+
cornerRadius: toggle.height / 2,
|
|
8083
|
+
borderWidth: 0,
|
|
8084
|
+
borderColor: "#000000"
|
|
8085
|
+
},
|
|
8086
|
+
toggle.style,
|
|
8087
|
+
tokens
|
|
8088
|
+
);
|
|
7457
8089
|
const signature = JSON.stringify([
|
|
7458
8090
|
trackSignature(
|
|
7459
8091
|
toggle.width,
|
|
7460
8092
|
toggle.height,
|
|
7461
8093
|
size,
|
|
7462
8094
|
chrome,
|
|
7463
|
-
|
|
7464
|
-
|
|
8095
|
+
accent,
|
|
8096
|
+
knobColor,
|
|
8097
|
+
variant
|
|
7465
8098
|
),
|
|
7466
8099
|
toggle.value
|
|
7467
8100
|
]);
|
|
@@ -7469,18 +8102,24 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7469
8102
|
world,
|
|
7470
8103
|
entityId,
|
|
7471
8104
|
signature,
|
|
7472
|
-
toggle
|
|
7473
|
-
|
|
8105
|
+
toggle,
|
|
8106
|
+
0,
|
|
7474
8107
|
size,
|
|
7475
8108
|
(ctx) => {
|
|
7476
|
-
drawChrome(
|
|
8109
|
+
drawChrome(
|
|
8110
|
+
ctx,
|
|
8111
|
+
layoutBox(toggle, 0, size.density),
|
|
8112
|
+
size.density,
|
|
8113
|
+
chrome,
|
|
8114
|
+
this.drawAssets
|
|
8115
|
+
);
|
|
7477
8116
|
}
|
|
7478
8117
|
);
|
|
7479
8118
|
if (!entry) return;
|
|
7480
8119
|
if (!entry.knob) {
|
|
7481
8120
|
entry.knob = this.makeDisc(
|
|
7482
8121
|
toggle.height * 0.4,
|
|
7483
|
-
|
|
8122
|
+
knobColor,
|
|
7484
8123
|
entry.face.parent,
|
|
7485
8124
|
CHILD_Z
|
|
7486
8125
|
);
|
|
@@ -7492,35 +8131,95 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7492
8131
|
knob.position.x += (target - knob.position.x) * (deltaTime > 0 ? ease : 1);
|
|
7493
8132
|
knob.position.z = CHILD_Z;
|
|
7494
8133
|
}
|
|
8134
|
+
/** Checkbox and radio: a box or ring at the left of the widget's area. */
|
|
8135
|
+
syncMarkToggle(world, entityId, toggle, accent, track, markColor) {
|
|
8136
|
+
const tokens = this.tokensFor(world, entityId);
|
|
8137
|
+
const radio = toggle.variant === "radio";
|
|
8138
|
+
const size = resolveCanvasSize(
|
|
8139
|
+
toggle.width,
|
|
8140
|
+
toggle.height,
|
|
8141
|
+
toggle.pixelDensity
|
|
8142
|
+
);
|
|
8143
|
+
const side = toggle.height;
|
|
8144
|
+
const chrome = resolveChrome(
|
|
8145
|
+
{
|
|
8146
|
+
backgroundColor: toggle.value ? accent : track,
|
|
8147
|
+
backgroundOpacity: 1,
|
|
8148
|
+
cornerRadius: radio ? side / 2 : side * 0.2,
|
|
8149
|
+
borderWidth: 0,
|
|
8150
|
+
borderColor: "#000000"
|
|
8151
|
+
},
|
|
8152
|
+
toggle.style,
|
|
8153
|
+
tokens
|
|
8154
|
+
);
|
|
8155
|
+
const signature = JSON.stringify([
|
|
8156
|
+
trackSignature(
|
|
8157
|
+
toggle.width,
|
|
8158
|
+
toggle.height,
|
|
8159
|
+
size,
|
|
8160
|
+
chrome,
|
|
8161
|
+
accent,
|
|
8162
|
+
markColor,
|
|
8163
|
+
toggle.variant ?? null
|
|
8164
|
+
),
|
|
8165
|
+
toggle.value
|
|
8166
|
+
]);
|
|
8167
|
+
this.rebuildIfChanged(world, entityId, signature, toggle, 0, size, (ctx) => {
|
|
8168
|
+
const px = side * size.density;
|
|
8169
|
+
const box = { x: 0, y: 0, w: px, h: px };
|
|
8170
|
+
drawChrome(ctx, box, size.density, chrome, this.drawAssets);
|
|
8171
|
+
if (!toggle.value) return;
|
|
8172
|
+
if (radio) drawDot(ctx, px / 2, px / 2, px * 0.24, markColor);
|
|
8173
|
+
else drawCheckMark(ctx, box, markColor);
|
|
8174
|
+
});
|
|
8175
|
+
}
|
|
7495
8176
|
syncSlider(world, entityId, slider) {
|
|
7496
|
-
const
|
|
8177
|
+
const tokens = this.tokensFor(world, entityId);
|
|
8178
|
+
const accent = resolveToken(slider.accentColor, tokens);
|
|
8179
|
+
const track = resolveToken(slider.trackColor, tokens);
|
|
8180
|
+
const knobColor = resolveToken(slider.knobColor, tokens);
|
|
8181
|
+
const size = resolveCanvasSize(
|
|
8182
|
+
slider.width,
|
|
8183
|
+
slider.height,
|
|
8184
|
+
slider.pixelDensity
|
|
8185
|
+
);
|
|
8186
|
+
const range = Math.max(1e-6, slider.max - slider.min);
|
|
8187
|
+
const t = Math.min(1, Math.max(0, (slider.value - slider.min) / range));
|
|
8188
|
+
if (slider.variant === "progress" || slider.variant === "ring") {
|
|
8189
|
+
this.syncMeter(world, entityId, slider, t, accent, track, knobColor);
|
|
8190
|
+
return;
|
|
8191
|
+
}
|
|
7497
8192
|
const trackThickness = slider.height * 0.32;
|
|
7498
8193
|
const knobRadius = slider.height * 0.45;
|
|
7499
8194
|
const usable = Math.max(1e-3, slider.width - slider.height);
|
|
7500
|
-
const chrome =
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
8195
|
+
const chrome = resolveChrome(
|
|
8196
|
+
{
|
|
8197
|
+
backgroundColor: track,
|
|
8198
|
+
backgroundOpacity: 1,
|
|
8199
|
+
cornerRadius: trackThickness / 2,
|
|
8200
|
+
borderWidth: 0,
|
|
8201
|
+
borderColor: "#000000"
|
|
8202
|
+
},
|
|
8203
|
+
void 0,
|
|
8204
|
+
null
|
|
8205
|
+
);
|
|
7507
8206
|
const signature = trackSignature(
|
|
7508
8207
|
slider.width,
|
|
7509
8208
|
slider.height,
|
|
7510
8209
|
size,
|
|
7511
8210
|
chrome,
|
|
7512
|
-
|
|
7513
|
-
|
|
8211
|
+
accent,
|
|
8212
|
+
knobColor,
|
|
8213
|
+
slider.variant ?? null
|
|
7514
8214
|
);
|
|
7515
8215
|
const entry = this.rebuildIfChanged(
|
|
7516
8216
|
world,
|
|
7517
8217
|
entityId,
|
|
7518
8218
|
signature,
|
|
7519
|
-
slider
|
|
7520
|
-
|
|
8219
|
+
slider,
|
|
8220
|
+
0,
|
|
7521
8221
|
size,
|
|
7522
8222
|
(ctx) => {
|
|
7523
|
-
ctx.clearRect(0, 0, size.pxWidth, size.pxHeight);
|
|
7524
8223
|
const trackWidthM = usable + trackThickness;
|
|
7525
8224
|
drawRoundedBar(
|
|
7526
8225
|
ctx,
|
|
@@ -7528,7 +8227,7 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7528
8227
|
(slider.height - trackThickness) / 2 * size.density,
|
|
7529
8228
|
trackWidthM * size.density,
|
|
7530
8229
|
trackThickness * size.density,
|
|
7531
|
-
|
|
8230
|
+
track
|
|
7532
8231
|
);
|
|
7533
8232
|
}
|
|
7534
8233
|
);
|
|
@@ -7537,13 +8236,13 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7537
8236
|
entry.fill = this.makeQuad(
|
|
7538
8237
|
1,
|
|
7539
8238
|
trackThickness,
|
|
7540
|
-
|
|
8239
|
+
accent,
|
|
7541
8240
|
entry.face.parent,
|
|
7542
8241
|
CHILD_Z / 2
|
|
7543
8242
|
);
|
|
7544
8243
|
entry.cap = this.makeDisc(
|
|
7545
8244
|
trackThickness / 2,
|
|
7546
|
-
|
|
8245
|
+
accent,
|
|
7547
8246
|
entry.face.parent,
|
|
7548
8247
|
CHILD_Z / 2,
|
|
7549
8248
|
Math.PI / 2,
|
|
@@ -7554,51 +8253,124 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7554
8253
|
if (!entry.knob) {
|
|
7555
8254
|
entry.knob = this.makeDisc(
|
|
7556
8255
|
knobRadius,
|
|
7557
|
-
|
|
8256
|
+
knobColor,
|
|
7558
8257
|
entry.face.parent,
|
|
7559
8258
|
CHILD_Z
|
|
7560
8259
|
);
|
|
7561
8260
|
}
|
|
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
8261
|
entry.knob.position.x = -usable / 2 + t * usable;
|
|
7565
8262
|
entry.knob.position.z = CHILD_Z;
|
|
7566
8263
|
entry.fill.scale.x = Math.max(1e-4, t * usable);
|
|
7567
8264
|
entry.fill.position.x = -usable / 2 + t * usable / 2;
|
|
7568
8265
|
entry.fill.position.z = CHILD_Z / 2;
|
|
7569
8266
|
}
|
|
8267
|
+
/**
|
|
8268
|
+
* Progress bars and rings. Unlike a slider these change rarely and have no
|
|
8269
|
+
* drag to keep smooth, so the value is drawn, in steps of half a percent.
|
|
8270
|
+
*/
|
|
8271
|
+
syncMeter(world, entityId, slider, t, accent, track, knobColor) {
|
|
8272
|
+
const size = resolveCanvasSize(
|
|
8273
|
+
slider.width,
|
|
8274
|
+
slider.height,
|
|
8275
|
+
slider.pixelDensity
|
|
8276
|
+
);
|
|
8277
|
+
const shown = Math.round(t * METER_STEPS) / METER_STEPS;
|
|
8278
|
+
const signature = JSON.stringify([
|
|
8279
|
+
slider.width,
|
|
8280
|
+
slider.height,
|
|
8281
|
+
size,
|
|
8282
|
+
slider.variant,
|
|
8283
|
+
accent,
|
|
8284
|
+
track,
|
|
8285
|
+
knobColor,
|
|
8286
|
+
shown
|
|
8287
|
+
]);
|
|
8288
|
+
this.rebuildIfChanged(world, entityId, signature, slider, 0, size, (ctx) => {
|
|
8289
|
+
const box = {
|
|
8290
|
+
x: 0,
|
|
8291
|
+
y: 0,
|
|
8292
|
+
w: size.pxWidth,
|
|
8293
|
+
h: size.pxHeight
|
|
8294
|
+
};
|
|
8295
|
+
if (slider.variant === "ring") {
|
|
8296
|
+
drawRing(ctx, box, shown, track, accent);
|
|
8297
|
+
return;
|
|
8298
|
+
}
|
|
8299
|
+
drawRoundedBar(ctx, 0, 0, box.w, box.h, track);
|
|
8300
|
+
if (shown <= 0) return;
|
|
8301
|
+
const fill = Math.max(box.h, box.w * shown);
|
|
8302
|
+
drawRoundedBar(ctx, 0, 0, fill, box.h, accent);
|
|
8303
|
+
});
|
|
8304
|
+
}
|
|
8305
|
+
/** The tokens in scope for a widget, nearest panel first. */
|
|
8306
|
+
tokensFor(world, entityId) {
|
|
8307
|
+
if (!this.anyTokens) return null;
|
|
8308
|
+
let merged = null;
|
|
8309
|
+
const visited = /* @__PURE__ */ new Set();
|
|
8310
|
+
let current = entityId;
|
|
8311
|
+
while (current !== null && !visited.has(current)) {
|
|
8312
|
+
visited.add(current);
|
|
8313
|
+
const tokens = world.getComponent(current, UIPanelComponent)?.tokens;
|
|
8314
|
+
if (tokens) merged = { ...tokens, ...merged ?? {} };
|
|
8315
|
+
const parent = world.getComponent(current, ParentId)?.value;
|
|
8316
|
+
current = typeof parent === "number" ? parent : null;
|
|
8317
|
+
}
|
|
8318
|
+
return merged;
|
|
8319
|
+
}
|
|
7570
8320
|
// ── Machinery ──────────────────────────────────────────────────────────────
|
|
7571
|
-
rebuildIfChanged(world, entityId, signature,
|
|
8321
|
+
rebuildIfChanged(world, entityId, signature, widget, bleed, size, draw, side = THREE26.FrontSide) {
|
|
7572
8322
|
const root = world.getComponent(entityId, Object3DRef)?.object;
|
|
7573
8323
|
if (!root) return null;
|
|
8324
|
+
const widthM = widget.width;
|
|
8325
|
+
const heightM = widget.height;
|
|
8326
|
+
const faceWidth = widthM + bleed * 2;
|
|
8327
|
+
const faceHeight = heightM + bleed * 2;
|
|
7574
8328
|
let entry = this.entries.get(entityId);
|
|
8329
|
+
if (entry) entry.opacity = widget.style?.opacity ?? 1;
|
|
7575
8330
|
if (entry && entry.signature === signature) return entry;
|
|
7576
8331
|
if (entry) this.disposeMovingParts(entry);
|
|
7577
8332
|
if (!entry) {
|
|
7578
8333
|
const canvas2 = this.createCanvas();
|
|
7579
|
-
const texture = new
|
|
8334
|
+
const texture = new THREE26.CanvasTexture(
|
|
7580
8335
|
canvas2
|
|
7581
8336
|
);
|
|
7582
8337
|
this.configureTexture(world, texture);
|
|
7583
|
-
const material = new
|
|
8338
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
7584
8339
|
map: texture,
|
|
7585
8340
|
transparent: true,
|
|
7586
8341
|
depthWrite: false,
|
|
7587
8342
|
// UI colours are authored absolutes; scene tone mapping would shift
|
|
7588
8343
|
// them (the classic "why is my white UI beige" bug).
|
|
7589
8344
|
toneMapped: false,
|
|
7590
|
-
side
|
|
7591
|
-
premultipliedAlpha:
|
|
8345
|
+
side,
|
|
8346
|
+
premultipliedAlpha: false,
|
|
8347
|
+
blending: THREE26.CustomBlending,
|
|
8348
|
+
blendSrc: THREE26.OneFactor,
|
|
8349
|
+
blendDst: THREE26.OneMinusSrcAlphaFactor,
|
|
8350
|
+
blendSrcAlpha: THREE26.OneFactor,
|
|
8351
|
+
blendDstAlpha: THREE26.OneMinusSrcAlphaFactor
|
|
7592
8352
|
});
|
|
7593
|
-
const face = new
|
|
7594
|
-
new
|
|
8353
|
+
const face = new THREE26.Mesh(
|
|
8354
|
+
new THREE26.PlaneGeometry(faceWidth, faceHeight),
|
|
7595
8355
|
material
|
|
7596
8356
|
);
|
|
7597
|
-
face
|
|
8357
|
+
tagPart(face, 16777215, true);
|
|
8358
|
+
face.raycast = () => {
|
|
8359
|
+
};
|
|
7598
8360
|
root.add(face);
|
|
8361
|
+
const hit = new THREE26.Mesh(
|
|
8362
|
+
new THREE26.PlaneGeometry(widthM, heightM),
|
|
8363
|
+
new THREE26.MeshBasicMaterial({ visible: false, side })
|
|
8364
|
+
);
|
|
8365
|
+
root.add(hit);
|
|
7599
8366
|
entry = {
|
|
7600
8367
|
signature: "",
|
|
8368
|
+
root,
|
|
8369
|
+
width: widthM,
|
|
8370
|
+
height: heightM,
|
|
8371
|
+
opacity: widget.style?.opacity ?? 1,
|
|
7601
8372
|
face,
|
|
8373
|
+
hit,
|
|
7602
8374
|
texture,
|
|
7603
8375
|
material,
|
|
7604
8376
|
canvas: canvas2,
|
|
@@ -7612,23 +8384,26 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7612
8384
|
if (canvas.width !== size.pxWidth || canvas.height !== size.pxHeight) {
|
|
7613
8385
|
canvas.width = size.pxWidth;
|
|
7614
8386
|
canvas.height = size.pxHeight;
|
|
8387
|
+
if (entry.signature) entry.texture.dispose();
|
|
7615
8388
|
}
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
}
|
|
8389
|
+
entry.width = widthM;
|
|
8390
|
+
entry.height = heightM;
|
|
8391
|
+
resizePlane(entry.face, faceWidth, faceHeight);
|
|
8392
|
+
resizePlane(entry.hit, widthM, heightM);
|
|
7621
8393
|
const ctx = canvas.getContext("2d");
|
|
7622
|
-
if (ctx)
|
|
8394
|
+
if (ctx) {
|
|
8395
|
+
ctx.clearRect(0, 0, size.pxWidth, size.pxHeight);
|
|
8396
|
+
draw(ctx);
|
|
8397
|
+
}
|
|
7623
8398
|
entry.texture.needsUpdate = true;
|
|
7624
8399
|
entry.signature = signature;
|
|
7625
8400
|
return entry;
|
|
7626
8401
|
}
|
|
7627
8402
|
configureTexture(world, texture) {
|
|
7628
|
-
texture.colorSpace =
|
|
8403
|
+
texture.colorSpace = THREE26.SRGBColorSpace;
|
|
7629
8404
|
texture.generateMipmaps = true;
|
|
7630
|
-
texture.minFilter =
|
|
7631
|
-
texture.magFilter =
|
|
8405
|
+
texture.minFilter = THREE26.LinearMipmapLinearFilter;
|
|
8406
|
+
texture.magFilter = THREE26.LinearFilter;
|
|
7632
8407
|
texture.premultiplyAlpha = true;
|
|
7633
8408
|
try {
|
|
7634
8409
|
const renderer = world.getRenderer();
|
|
@@ -7639,7 +8414,7 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7639
8414
|
}
|
|
7640
8415
|
makeQuad(widthM, heightM, color, parent, z) {
|
|
7641
8416
|
return this.addPart(
|
|
7642
|
-
new
|
|
8417
|
+
new THREE26.PlaneGeometry(widthM, heightM),
|
|
7643
8418
|
color,
|
|
7644
8419
|
parent,
|
|
7645
8420
|
z
|
|
@@ -7648,24 +8423,23 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7648
8423
|
/** A filled disc (or arc segment, for the fill's rounded cap). */
|
|
7649
8424
|
makeDisc(radiusM, color, parent, z, thetaStart = 0, thetaLength = Math.PI * 2) {
|
|
7650
8425
|
return this.addPart(
|
|
7651
|
-
new
|
|
8426
|
+
new THREE26.CircleGeometry(radiusM, 32, thetaStart, thetaLength),
|
|
7652
8427
|
color,
|
|
7653
8428
|
parent,
|
|
7654
8429
|
z
|
|
7655
8430
|
);
|
|
7656
8431
|
}
|
|
7657
8432
|
addPart(geometry, color, parent, z) {
|
|
7658
|
-
const mesh = new
|
|
8433
|
+
const mesh = new THREE26.Mesh(
|
|
7659
8434
|
geometry,
|
|
7660
|
-
new
|
|
8435
|
+
new THREE26.MeshBasicMaterial({
|
|
7661
8436
|
color,
|
|
7662
8437
|
transparent: true,
|
|
7663
8438
|
depthWrite: false,
|
|
7664
|
-
toneMapped: false
|
|
7665
|
-
side: THREE19.DoubleSide
|
|
8439
|
+
toneMapped: false
|
|
7666
8440
|
})
|
|
7667
8441
|
);
|
|
7668
|
-
mesh
|
|
8442
|
+
tagPart(mesh, color);
|
|
7669
8443
|
mesh.position.z = z;
|
|
7670
8444
|
mesh.raycast = () => {
|
|
7671
8445
|
};
|
|
@@ -7696,22 +8470,144 @@ var _UIPanelSystem = class _UIPanelSystem {
|
|
|
7696
8470
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
7697
8471
|
if (!transform || !object) return;
|
|
7698
8472
|
const camera = world.getCamera();
|
|
7699
|
-
const cam = new
|
|
7700
|
-
const self = new
|
|
8473
|
+
const cam = new THREE26.Vector3();
|
|
8474
|
+
const self = new THREE26.Vector3();
|
|
7701
8475
|
camera.getWorldPosition(cam);
|
|
7702
8476
|
object.getWorldPosition(self);
|
|
7703
8477
|
transform.rotation.y = Math.atan2(cam.x - self.x, cam.z - self.z);
|
|
7704
8478
|
}
|
|
8479
|
+
/**
|
|
8480
|
+
* Stamp every widget's meshes with this frame's paint order. Written each
|
|
8481
|
+
* frame because the eye moves: the order between trees can change at any
|
|
8482
|
+
* time, and a plain property write costs less than checking it.
|
|
8483
|
+
*/
|
|
8484
|
+
applyPaintOrder(world) {
|
|
8485
|
+
if (this.entries.size === 0) return;
|
|
8486
|
+
const camera = world.getCamera();
|
|
8487
|
+
camera.getWorldPosition(eyeScratch);
|
|
8488
|
+
const nodes = [...this.entries.keys()].map((id) => ({
|
|
8489
|
+
id,
|
|
8490
|
+
parent: nearestWidgetAncestor(world, id)
|
|
8491
|
+
}));
|
|
8492
|
+
const trees = buildPaintTrees(nodes);
|
|
8493
|
+
const rects = /* @__PURE__ */ new Map();
|
|
8494
|
+
for (const tree of trees) {
|
|
8495
|
+
const entry = this.entries.get(tree.rootId);
|
|
8496
|
+
if (entry) rects.set(tree.rootId, rootRect(tree.rootId, entry));
|
|
8497
|
+
}
|
|
8498
|
+
const slots = assignPaintOrder(trees, rects, eyeScratch);
|
|
8499
|
+
this.framesUntilDescendantWalk -= 1;
|
|
8500
|
+
const walkDescendants = this.framesUntilDescendantWalk <= 0;
|
|
8501
|
+
if (walkDescendants) {
|
|
8502
|
+
this.framesUntilDescendantWalk = DESCENDANT_WALK_INTERVAL;
|
|
8503
|
+
}
|
|
8504
|
+
const widgetRoots = /* @__PURE__ */ new Set();
|
|
8505
|
+
if (walkDescendants) {
|
|
8506
|
+
for (const entry of this.entries.values()) widgetRoots.add(entry.root);
|
|
8507
|
+
}
|
|
8508
|
+
for (const [entityId, entry] of this.entries) {
|
|
8509
|
+
const slot = slots.get(entityId);
|
|
8510
|
+
if (!slot) continue;
|
|
8511
|
+
entry.face.renderOrder = slot.face;
|
|
8512
|
+
for (const part of [entry.knob, entry.fill, entry.cap]) {
|
|
8513
|
+
if (part) part.renderOrder = slot.parts;
|
|
8514
|
+
}
|
|
8515
|
+
if (walkDescendants) stampDescendants(entry.root, slot, widgetRoots);
|
|
8516
|
+
}
|
|
8517
|
+
const effective = /* @__PURE__ */ new Map();
|
|
8518
|
+
const parentOf = new Map(nodes.map((node) => [node.id, node.parent]));
|
|
8519
|
+
for (const tree of trees) {
|
|
8520
|
+
for (const id of tree.order) {
|
|
8521
|
+
const entry = this.entries.get(id);
|
|
8522
|
+
if (!entry) continue;
|
|
8523
|
+
const parent = parentOf.get(id);
|
|
8524
|
+
const inherited = parent != null ? effective.get(parent) ?? 1 : 1;
|
|
8525
|
+
const opacity = entry.opacity * inherited;
|
|
8526
|
+
effective.set(id, opacity);
|
|
8527
|
+
for (const mesh of [entry.face, entry.knob, entry.fill, entry.cap]) {
|
|
8528
|
+
if (!mesh) continue;
|
|
8529
|
+
const tag = mesh.userData[UI_PART_KEY];
|
|
8530
|
+
if (tag.opacity === opacity) continue;
|
|
8531
|
+
tag.opacity = opacity;
|
|
8532
|
+
applyPartColor(mesh, tag);
|
|
8533
|
+
}
|
|
8534
|
+
}
|
|
8535
|
+
}
|
|
8536
|
+
}
|
|
7705
8537
|
destroyEntry(entry) {
|
|
7706
8538
|
this.disposeMovingParts(entry);
|
|
7707
8539
|
entry.face.removeFromParent();
|
|
7708
8540
|
entry.face.geometry.dispose();
|
|
7709
8541
|
entry.face.material.dispose();
|
|
8542
|
+
entry.hit.removeFromParent();
|
|
8543
|
+
entry.hit.geometry.dispose();
|
|
8544
|
+
entry.hit.material.dispose();
|
|
7710
8545
|
entry.texture.dispose();
|
|
7711
8546
|
}
|
|
7712
8547
|
};
|
|
7713
8548
|
__name(_UIPanelSystem, "UIPanelSystem");
|
|
7714
8549
|
var UIPanelSystem = _UIPanelSystem;
|
|
8550
|
+
var eyeScratch = new THREE26.Vector3();
|
|
8551
|
+
function tagPart(mesh, color, premultiplied = false) {
|
|
8552
|
+
const tag = {
|
|
8553
|
+
baseColor: new THREE26.Color(color),
|
|
8554
|
+
tint: 1,
|
|
8555
|
+
opacity: 1,
|
|
8556
|
+
premultiplied
|
|
8557
|
+
};
|
|
8558
|
+
mesh.userData[UI_PART_KEY] = tag;
|
|
8559
|
+
}
|
|
8560
|
+
__name(tagPart, "tagPart");
|
|
8561
|
+
function resizePlane(mesh, width, height) {
|
|
8562
|
+
const params = mesh.geometry.parameters;
|
|
8563
|
+
if (params.width === width && params.height === height) return;
|
|
8564
|
+
mesh.geometry.dispose();
|
|
8565
|
+
mesh.geometry = new THREE26.PlaneGeometry(width, height);
|
|
8566
|
+
}
|
|
8567
|
+
__name(resizePlane, "resizePlane");
|
|
8568
|
+
function layoutBox(widget, bleed, density) {
|
|
8569
|
+
return {
|
|
8570
|
+
x: bleed * density,
|
|
8571
|
+
y: bleed * density,
|
|
8572
|
+
w: widget.width * density,
|
|
8573
|
+
h: widget.height * density
|
|
8574
|
+
};
|
|
8575
|
+
}
|
|
8576
|
+
__name(layoutBox, "layoutBox");
|
|
8577
|
+
function familyOf(font) {
|
|
8578
|
+
return font ? uiFontFamily(font) : null;
|
|
8579
|
+
}
|
|
8580
|
+
__name(familyOf, "familyOf");
|
|
8581
|
+
function imagesLoaded(chrome) {
|
|
8582
|
+
return styleAssets(chrome, null).images.map((src) => !!uiImage(src));
|
|
8583
|
+
}
|
|
8584
|
+
__name(imagesLoaded, "imagesLoaded");
|
|
8585
|
+
function rootRect(id, entry) {
|
|
8586
|
+
const e = entry.root.matrixWorld.elements;
|
|
8587
|
+
const halfW = entry.width / 2;
|
|
8588
|
+
const halfH = entry.height / 2;
|
|
8589
|
+
return {
|
|
8590
|
+
id,
|
|
8591
|
+
center: { x: e[12], y: e[13], z: e[14] },
|
|
8592
|
+
halfX: { x: e[0] * halfW, y: e[1] * halfW, z: e[2] * halfW },
|
|
8593
|
+
halfY: { x: e[4] * halfH, y: e[5] * halfH, z: e[6] * halfH }
|
|
8594
|
+
};
|
|
8595
|
+
}
|
|
8596
|
+
__name(rootRect, "rootRect");
|
|
8597
|
+
function stampDescendants(root, slot, widgetRoots) {
|
|
8598
|
+
for (const child of root.children) {
|
|
8599
|
+
if (widgetRoots.has(child) || child.userData[UI_PART_KEY]) continue;
|
|
8600
|
+
const material = child.material;
|
|
8601
|
+
const transparent = Array.isArray(material) ? material.some((m) => m.transparent) : material?.transparent === true;
|
|
8602
|
+
const untouched = child.renderOrder === 0 || child.userData[PAINT_STAMP_KEY] === child.renderOrder;
|
|
8603
|
+
if (transparent && untouched) {
|
|
8604
|
+
child.renderOrder = slot.descendants;
|
|
8605
|
+
child.userData[PAINT_STAMP_KEY] = slot.descendants;
|
|
8606
|
+
}
|
|
8607
|
+
stampDescendants(child, slot, widgetRoots);
|
|
8608
|
+
}
|
|
8609
|
+
}
|
|
8610
|
+
__name(stampDescendants, "stampDescendants");
|
|
7715
8611
|
var _XRHitTestSystem = class _XRHitTestSystem {
|
|
7716
8612
|
constructor() {
|
|
7717
8613
|
this.sources = /* @__PURE__ */ new Map();
|
|
@@ -7748,12 +8644,12 @@ var _XRHitTestSystem = class _XRHitTestSystem {
|
|
|
7748
8644
|
if (!hits || hits.length === 0) continue;
|
|
7749
8645
|
const pose = hits[0].getPose(referenceSpace);
|
|
7750
8646
|
if (!pose) continue;
|
|
7751
|
-
const matrix = new
|
|
8647
|
+
const matrix = new THREE26.Matrix4().fromArray(
|
|
7752
8648
|
pose.transform.matrix
|
|
7753
8649
|
);
|
|
7754
|
-
const position = new
|
|
7755
|
-
const quaternion = new
|
|
7756
|
-
matrix.decompose(position, quaternion, new
|
|
8650
|
+
const position = new THREE26.Vector3();
|
|
8651
|
+
const quaternion = new THREE26.Quaternion();
|
|
8652
|
+
matrix.decompose(position, quaternion, new THREE26.Vector3());
|
|
7757
8653
|
this.results.set(key, { position, quaternion });
|
|
7758
8654
|
}
|
|
7759
8655
|
}
|
|
@@ -7827,8 +8723,8 @@ var _XRAnchorSystem = class _XRAnchorSystem {
|
|
|
7827
8723
|
/** Per-anchor head-glue gates — see XREnvironmentSystem's TrackedEntry. */
|
|
7828
8724
|
this.gates = /* @__PURE__ */ new Map();
|
|
7829
8725
|
this.presenting = false;
|
|
7830
|
-
this.tmpViewerMatrix = new
|
|
7831
|
-
this.tmpViewPos = new
|
|
8726
|
+
this.tmpViewerMatrix = new THREE26.Matrix4();
|
|
8727
|
+
this.tmpViewPos = new THREE26.Vector3();
|
|
7832
8728
|
}
|
|
7833
8729
|
update(world, deltaTime = 0) {
|
|
7834
8730
|
const presenting = world.isXrPresenting();
|
|
@@ -7902,8 +8798,8 @@ var _XRAnchorSystem = class _XRAnchorSystem {
|
|
|
7902
8798
|
if (typeof frame.createAnchor !== "function") return;
|
|
7903
8799
|
const RigidTransform = globalThis.XRRigidTransform;
|
|
7904
8800
|
if (!RigidTransform) return;
|
|
7905
|
-
const quaternion = new
|
|
7906
|
-
new
|
|
8801
|
+
const quaternion = new THREE26.Quaternion().setFromEuler(
|
|
8802
|
+
new THREE26.Euler(
|
|
7907
8803
|
transform.rotation.x,
|
|
7908
8804
|
transform.rotation.y,
|
|
7909
8805
|
transform.rotation.z,
|
|
@@ -7946,13 +8842,13 @@ var _XRAnchorSystem = class _XRAnchorSystem {
|
|
|
7946
8842
|
};
|
|
7947
8843
|
__name(_XRAnchorSystem, "XRAnchorSystem");
|
|
7948
8844
|
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
|
|
8845
|
+
var _q = new THREE26.Quaternion();
|
|
8846
|
+
var _q2 = new THREE26.Quaternion();
|
|
8847
|
+
var _s = new THREE26.Vector3();
|
|
8848
|
+
var _e = new THREE26.Vector3();
|
|
8849
|
+
var _w = new THREE26.Vector3();
|
|
8850
|
+
var _v = new THREE26.Vector3();
|
|
8851
|
+
var _p = new THREE26.Vector3();
|
|
7956
8852
|
function setWorldQuaternion(o, q) {
|
|
7957
8853
|
if (o.parent) {
|
|
7958
8854
|
o.parent.getWorldQuaternion(_q2).invert();
|
|
@@ -7977,31 +8873,31 @@ function twoBoneIK(upper, lower, end, target, pole) {
|
|
|
7977
8873
|
if (a < 1e-6 || b < 1e-6) return target.distanceTo(_w);
|
|
7978
8874
|
const toT = _v.subVectors(target, _s);
|
|
7979
8875
|
const want = toT.length();
|
|
7980
|
-
const c =
|
|
8876
|
+
const c = THREE26.MathUtils.clamp(want, Math.abs(a - b) + 1e-4, a + b - 1e-4);
|
|
7981
8877
|
const dir = toT.divideScalar(want || 1).clone();
|
|
7982
8878
|
const pv = _p.subVectors(pole, _s);
|
|
7983
8879
|
pv.addScaledVector(dir, -pv.dot(dir));
|
|
7984
8880
|
if (pv.lengthSq() < 1e-8) pv.set(0, -1, 0).addScaledVector(dir, dir.y);
|
|
7985
8881
|
pv.normalize();
|
|
7986
|
-
const cosA =
|
|
8882
|
+
const cosA = THREE26.MathUtils.clamp((a * a + c * c - b * b) / (2 * a * c), -1, 1);
|
|
7987
8883
|
const joint = _s.clone().addScaledVector(dir, a * cosA).addScaledVector(pv, a * Math.sqrt(1 - cosA * cosA));
|
|
7988
|
-
turn(upper, new
|
|
8884
|
+
turn(upper, new THREE26.Quaternion().setFromUnitVectors(_e.clone().sub(_s).normalize(), joint.clone().sub(_s).normalize()));
|
|
7989
8885
|
lower.getWorldPosition(_e);
|
|
7990
8886
|
end.getWorldPosition(_w);
|
|
7991
8887
|
const reach = _s.clone().addScaledVector(dir, c);
|
|
7992
|
-
turn(lower, new
|
|
8888
|
+
turn(lower, new THREE26.Quaternion().setFromUnitVectors(_w.clone().sub(_e).normalize(), reach.clone().sub(_e).normalize()));
|
|
7993
8889
|
return want - c;
|
|
7994
8890
|
}
|
|
7995
8891
|
__name(twoBoneIK, "twoBoneIK");
|
|
7996
|
-
function gripQuaternion(axis, back, forearm, out = new
|
|
8892
|
+
function gripQuaternion(axis, back, forearm, out = new THREE26.Quaternion()) {
|
|
7997
8893
|
let X = axis.clone();
|
|
7998
8894
|
const Z = back.clone().addScaledVector(X, -back.dot(X)).normalize().negate();
|
|
7999
|
-
let Y = new
|
|
8895
|
+
let Y = new THREE26.Vector3().crossVectors(Z, X);
|
|
8000
8896
|
if (Y.dot(forearm) < 0) {
|
|
8001
8897
|
X = X.negate();
|
|
8002
8898
|
Y = Y.negate();
|
|
8003
8899
|
}
|
|
8004
|
-
return out.setFromRotationMatrix(new
|
|
8900
|
+
return out.setFromRotationMatrix(new THREE26.Matrix4().makeBasis(X, Y, Z));
|
|
8005
8901
|
}
|
|
8006
8902
|
__name(gripQuaternion, "gripQuaternion");
|
|
8007
8903
|
|
|
@@ -8012,10 +8908,10 @@ var LIMB_BONES = {
|
|
|
8012
8908
|
leftFoot: ["leftUpperLeg", "leftLowerLeg", "leftFoot"],
|
|
8013
8909
|
rightFoot: ["rightUpperLeg", "rightLowerLeg", "rightFoot"]
|
|
8014
8910
|
};
|
|
8015
|
-
var _t = new
|
|
8016
|
-
var _p2 = new
|
|
8017
|
-
var _q3 = new
|
|
8018
|
-
var _pq = new
|
|
8911
|
+
var _t = new THREE26.Vector3();
|
|
8912
|
+
var _p2 = new THREE26.Vector3();
|
|
8913
|
+
var _q3 = new THREE26.Quaternion();
|
|
8914
|
+
var _pq = new THREE26.Quaternion();
|
|
8019
8915
|
var _IKSystem = class _IKSystem {
|
|
8020
8916
|
constructor() {
|
|
8021
8917
|
this.runtimes = /* @__PURE__ */ new Map();
|
|
@@ -8076,7 +8972,7 @@ var _IKSystem = class _IKSystem {
|
|
|
8076
8972
|
const [upper, lower, end] = limb.bones;
|
|
8077
8973
|
for (const bone of [upper, lower, end]) {
|
|
8078
8974
|
if (!runtime.written.has(bone)) {
|
|
8079
|
-
runtime.written.set(bone, { before: bone.quaternion.clone(), written: new
|
|
8975
|
+
runtime.written.set(bone, { before: bone.quaternion.clone(), written: new THREE26.Quaternion() });
|
|
8080
8976
|
}
|
|
8081
8977
|
}
|
|
8082
8978
|
const animated = [upper.quaternion.clone(), lower.quaternion.clone(), end.quaternion.clone()];
|
|
@@ -8114,9 +9010,9 @@ var IKSystem = _IKSystem;
|
|
|
8114
9010
|
function buildGeometry2(area) {
|
|
8115
9011
|
if (area.shape === "circle") {
|
|
8116
9012
|
const radius = Math.max(5e-3, area.width / 2);
|
|
8117
|
-
return new
|
|
9013
|
+
return new THREE26.CircleGeometry(radius, 48);
|
|
8118
9014
|
}
|
|
8119
|
-
return new
|
|
9015
|
+
return new THREE26.PlaneGeometry(
|
|
8120
9016
|
Math.max(0.01, area.width),
|
|
8121
9017
|
Math.max(0.01, area.depth)
|
|
8122
9018
|
);
|
|
@@ -8133,13 +9029,13 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
|
|
|
8133
9029
|
update(world) {
|
|
8134
9030
|
const entityIds = world.query(VRTeleportAreaComponent, Object3DRef);
|
|
8135
9031
|
const alive = new Set(entityIds);
|
|
8136
|
-
for (const
|
|
8137
|
-
if (!alive.has(
|
|
9032
|
+
for (const tracked2 of this.signatures.keys()) {
|
|
9033
|
+
if (!alive.has(tracked2)) this.signatures.delete(tracked2);
|
|
8138
9034
|
}
|
|
8139
9035
|
for (const entityId of entityIds) {
|
|
8140
9036
|
const area = world.getComponent(entityId, VRTeleportAreaComponent);
|
|
8141
9037
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
8142
|
-
if (!area || !(object instanceof
|
|
9038
|
+
if (!area || !(object instanceof THREE26.Mesh)) continue;
|
|
8143
9039
|
const signature = signatureOf(area);
|
|
8144
9040
|
if (this.signatures.get(entityId) === signature) continue;
|
|
8145
9041
|
this.signatures.set(entityId, signature);
|
|
@@ -8151,18 +9047,18 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
|
|
|
8151
9047
|
__name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
|
|
8152
9048
|
var VRTeleportAreaSystem = _VRTeleportAreaSystem;
|
|
8153
9049
|
function createHandMaterial(preset, options) {
|
|
8154
|
-
const color = new
|
|
9050
|
+
const color = new THREE26.Color(options.color);
|
|
8155
9051
|
switch (preset) {
|
|
8156
9052
|
case "ghost":
|
|
8157
|
-
return new
|
|
9053
|
+
return new THREE26.MeshBasicMaterial({
|
|
8158
9054
|
color,
|
|
8159
9055
|
transparent: true,
|
|
8160
9056
|
opacity: Math.min(1, Math.max(0.05, options.opacity * 0.45)),
|
|
8161
9057
|
depthWrite: false,
|
|
8162
|
-
side:
|
|
9058
|
+
side: THREE26.DoubleSide
|
|
8163
9059
|
});
|
|
8164
9060
|
case "neon":
|
|
8165
|
-
return new
|
|
9061
|
+
return new THREE26.MeshStandardMaterial({
|
|
8166
9062
|
color,
|
|
8167
9063
|
emissive: color,
|
|
8168
9064
|
emissiveIntensity: Math.max(0.5, options.emissiveIntensity || 2),
|
|
@@ -8172,7 +9068,7 @@ function createHandMaterial(preset, options) {
|
|
|
8172
9068
|
opacity: options.opacity
|
|
8173
9069
|
});
|
|
8174
9070
|
case "skeleton":
|
|
8175
|
-
return new
|
|
9071
|
+
return new THREE26.MeshBasicMaterial({
|
|
8176
9072
|
color,
|
|
8177
9073
|
wireframe: true,
|
|
8178
9074
|
transparent: true,
|
|
@@ -8180,7 +9076,7 @@ function createHandMaterial(preset, options) {
|
|
|
8180
9076
|
});
|
|
8181
9077
|
case "custom":
|
|
8182
9078
|
case "default":
|
|
8183
|
-
return new
|
|
9079
|
+
return new THREE26.MeshStandardMaterial({
|
|
8184
9080
|
color,
|
|
8185
9081
|
roughness: 0.85,
|
|
8186
9082
|
metalness: 0,
|
|
@@ -8188,10 +9084,10 @@ function createHandMaterial(preset, options) {
|
|
|
8188
9084
|
emissiveIntensity: Math.max(0, options.emissiveIntensity),
|
|
8189
9085
|
transparent: options.opacity < 1,
|
|
8190
9086
|
opacity: options.opacity,
|
|
8191
|
-
side:
|
|
9087
|
+
side: THREE26.DoubleSide
|
|
8192
9088
|
});
|
|
8193
9089
|
default: {
|
|
8194
|
-
return new
|
|
9090
|
+
return new THREE26.MeshStandardMaterial({ color });
|
|
8195
9091
|
}
|
|
8196
9092
|
}
|
|
8197
9093
|
}
|
|
@@ -8216,9 +9112,9 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8216
9112
|
constructor(options) {
|
|
8217
9113
|
this.controllerModelFactory = new XRControllerModelFactory();
|
|
8218
9114
|
this.handModelFactory = new XRHandModelFactory();
|
|
8219
|
-
this.group = new
|
|
9115
|
+
this.group = new THREE26.Group();
|
|
8220
9116
|
/** Reused so a per-frame colour compare allocates nothing. */
|
|
8221
|
-
this.rayColorScratch = new
|
|
9117
|
+
this.rayColorScratch = new THREE26.Color();
|
|
8222
9118
|
this.slots = /* @__PURE__ */ new Map();
|
|
8223
9119
|
this.attachedTo = null;
|
|
8224
9120
|
/** Last applied preset signature, so materials rebuild only on real change. */
|
|
@@ -8355,8 +9251,8 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8355
9251
|
*/
|
|
8356
9252
|
fitRayToHover(ray, side) {
|
|
8357
9253
|
const hover = this.interactionSystem?.getHoverFor(side) ?? null;
|
|
8358
|
-
const
|
|
8359
|
-
ray.scale.z =
|
|
9254
|
+
const length2 = hover && Number.isFinite(hover.distance) && hover.distance > 0 ? Math.min(hover.distance, RAY_LENGTH) : RAY_LENGTH;
|
|
9255
|
+
ray.scale.z = length2;
|
|
8360
9256
|
}
|
|
8361
9257
|
/** Lazily build per-slot visuals; the device reports profiles late. */
|
|
8362
9258
|
ensureSlots(world) {
|
|
@@ -8405,17 +9301,17 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8405
9301
|
* without pulling in a line-rendering extension.
|
|
8406
9302
|
*/
|
|
8407
9303
|
createRay() {
|
|
8408
|
-
const geometry = new
|
|
9304
|
+
const geometry = new THREE26.CylinderGeometry(RAY_RADIUS, RAY_RADIUS, 1, 8, 1);
|
|
8409
9305
|
geometry.rotateX(-Math.PI / 2);
|
|
8410
9306
|
geometry.translate(0, 0, -0.5);
|
|
8411
|
-
const material = new
|
|
9307
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
8412
9308
|
color: "#4da3ff",
|
|
8413
9309
|
transparent: true,
|
|
8414
9310
|
opacity: 0.75,
|
|
8415
9311
|
depthTest: false,
|
|
8416
9312
|
depthWrite: false
|
|
8417
9313
|
});
|
|
8418
|
-
const mesh = new
|
|
9314
|
+
const mesh = new THREE26.Mesh(geometry, material);
|
|
8419
9315
|
mesh.name = "XRPointerRay";
|
|
8420
9316
|
mesh.renderOrder = 999;
|
|
8421
9317
|
mesh.visible = false;
|
|
@@ -8446,14 +9342,14 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
8446
9342
|
__name(_XRControllerVisualSystem, "XRControllerVisualSystem");
|
|
8447
9343
|
var XRControllerVisualSystem = _XRControllerVisualSystem;
|
|
8448
9344
|
var MARKER_RADIUS = 0.28;
|
|
8449
|
-
var ACCENT = new
|
|
8450
|
-
var SEGMENT_AXIS = new
|
|
9345
|
+
var ACCENT = new THREE26.Color("#4da3ff");
|
|
9346
|
+
var SEGMENT_AXIS = new THREE26.Vector3(0, 1, 0);
|
|
8451
9347
|
var HEAD_CLEARANCE = 0.25;
|
|
8452
9348
|
var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
8453
9349
|
constructor(locomotionSystem) {
|
|
8454
|
-
this.group = new
|
|
9350
|
+
this.group = new THREE26.Group();
|
|
8455
9351
|
/** Holds the segment chain that draws the arc. */
|
|
8456
|
-
this.arc = new
|
|
9352
|
+
this.arc = new THREE26.Group();
|
|
8457
9353
|
/**
|
|
8458
9354
|
* Unit cylinder along +Y, reused by every segment.
|
|
8459
9355
|
*
|
|
@@ -8462,14 +9358,14 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8462
9358
|
* scaled cylinders gives real thickness while rebuilding no geometry: each
|
|
8463
9359
|
* frame only moves, rotates and scales meshes that already exist.
|
|
8464
9360
|
*/
|
|
8465
|
-
this.segmentGeometry = new
|
|
9361
|
+
this.segmentGeometry = new THREE26.CylinderGeometry(1, 1, 1, 6, 1);
|
|
8466
9362
|
this.segments = [];
|
|
8467
|
-
this.marker = new
|
|
9363
|
+
this.marker = new THREE26.Group();
|
|
8468
9364
|
this.attached = false;
|
|
8469
|
-
this.scratchDirection = new
|
|
8470
|
-
this.scratchHead = new
|
|
8471
|
-
this.validColor = new
|
|
8472
|
-
this.invalidColor = new
|
|
9365
|
+
this.scratchDirection = new THREE26.Vector3();
|
|
9366
|
+
this.scratchHead = new THREE26.Vector3();
|
|
9367
|
+
this.validColor = new THREE26.Color();
|
|
9368
|
+
this.invalidColor = new THREE26.Color();
|
|
8473
9369
|
this.locomotionSystem = locomotionSystem;
|
|
8474
9370
|
this.group.name = "XRTeleportVisuals";
|
|
8475
9371
|
this.group.userData.ecsPreviewHidden = true;
|
|
@@ -8527,8 +9423,8 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8527
9423
|
const from = curve[i];
|
|
8528
9424
|
const to = curve[i + 1];
|
|
8529
9425
|
this.scratchDirection.subVectors(to, from);
|
|
8530
|
-
const
|
|
8531
|
-
if (
|
|
9426
|
+
const length2 = this.scratchDirection.length();
|
|
9427
|
+
if (length2 < 1e-6) {
|
|
8532
9428
|
segment.visible = false;
|
|
8533
9429
|
continue;
|
|
8534
9430
|
}
|
|
@@ -8536,9 +9432,9 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8536
9432
|
segment.position.copy(from).addScaledVector(this.scratchDirection, 0.5);
|
|
8537
9433
|
segment.quaternion.setFromUnitVectors(
|
|
8538
9434
|
SEGMENT_AXIS,
|
|
8539
|
-
this.scratchDirection.divideScalar(
|
|
9435
|
+
this.scratchDirection.divideScalar(length2)
|
|
8540
9436
|
);
|
|
8541
|
-
segment.scale.set(radius,
|
|
9437
|
+
segment.scale.set(radius, length2, radius);
|
|
8542
9438
|
const t = needed > 1 ? i / (needed - 1) : 0;
|
|
8543
9439
|
const fade = 1 - t * 0.75;
|
|
8544
9440
|
segment.material.color.copy(tint).multiplyScalar(fade);
|
|
@@ -8547,12 +9443,12 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8547
9443
|
/** Grow the segment pool to cover the current arc. */
|
|
8548
9444
|
ensureSegments(count) {
|
|
8549
9445
|
while (this.segments.length < count) {
|
|
8550
|
-
const material = new
|
|
9446
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
8551
9447
|
transparent: true,
|
|
8552
9448
|
depthTest: false,
|
|
8553
9449
|
depthWrite: false
|
|
8554
9450
|
});
|
|
8555
|
-
const mesh = new
|
|
9451
|
+
const mesh = new THREE26.Mesh(this.segmentGeometry, material);
|
|
8556
9452
|
mesh.frustumCulled = false;
|
|
8557
9453
|
mesh.renderOrder = 998;
|
|
8558
9454
|
mesh.raycast = () => {
|
|
@@ -8576,33 +9472,33 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
8576
9472
|
return world.getComponent(entityId, XRRigComponent) ?? null;
|
|
8577
9473
|
}
|
|
8578
9474
|
createRing() {
|
|
8579
|
-
const geometry = new
|
|
9475
|
+
const geometry = new THREE26.RingGeometry(
|
|
8580
9476
|
MARKER_RADIUS * 0.72,
|
|
8581
9477
|
MARKER_RADIUS,
|
|
8582
9478
|
48
|
|
8583
9479
|
);
|
|
8584
9480
|
geometry.rotateX(-Math.PI / 2);
|
|
8585
|
-
return new
|
|
9481
|
+
return new THREE26.Mesh(
|
|
8586
9482
|
geometry,
|
|
8587
|
-
new
|
|
9483
|
+
new THREE26.MeshBasicMaterial({
|
|
8588
9484
|
color: ACCENT,
|
|
8589
9485
|
transparent: true,
|
|
8590
9486
|
opacity: 0.9,
|
|
8591
|
-
side:
|
|
9487
|
+
side: THREE26.DoubleSide,
|
|
8592
9488
|
depthTest: false
|
|
8593
9489
|
})
|
|
8594
9490
|
);
|
|
8595
9491
|
}
|
|
8596
9492
|
createDot() {
|
|
8597
|
-
const geometry = new
|
|
9493
|
+
const geometry = new THREE26.CircleGeometry(MARKER_RADIUS * 0.16, 24);
|
|
8598
9494
|
geometry.rotateX(-Math.PI / 2);
|
|
8599
|
-
return new
|
|
9495
|
+
return new THREE26.Mesh(
|
|
8600
9496
|
geometry,
|
|
8601
|
-
new
|
|
9497
|
+
new THREE26.MeshBasicMaterial({
|
|
8602
9498
|
color: ACCENT,
|
|
8603
9499
|
transparent: true,
|
|
8604
9500
|
opacity: 0.55,
|
|
8605
|
-
side:
|
|
9501
|
+
side: THREE26.DoubleSide,
|
|
8606
9502
|
depthTest: false
|
|
8607
9503
|
})
|
|
8608
9504
|
);
|
|
@@ -8713,7 +9609,7 @@ function boneDirections(joints, finger) {
|
|
|
8713
9609
|
const from = joints[chain[i - 1]];
|
|
8714
9610
|
const to = joints[chain[i]];
|
|
8715
9611
|
if (!from || !to) return null;
|
|
8716
|
-
const direction = new
|
|
9612
|
+
const direction = new THREE26.Vector3().subVectors(to, from);
|
|
8717
9613
|
if (direction.lengthSq() < 1e-12) return null;
|
|
8718
9614
|
directions.push(direction.normalize());
|
|
8719
9615
|
}
|
|
@@ -8786,8 +9682,8 @@ function computeSpread(joints, a, b) {
|
|
|
8786
9682
|
const bBase = joints[METACARPAL_JOINTS[b]];
|
|
8787
9683
|
const bTip = joints[TIP_JOINTS[b]];
|
|
8788
9684
|
if (!aBase || !aTip || !bBase || !bTip) return null;
|
|
8789
|
-
const dirA = new
|
|
8790
|
-
const dirB = new
|
|
9685
|
+
const dirA = new THREE26.Vector3().subVectors(aTip, aBase);
|
|
9686
|
+
const dirB = new THREE26.Vector3().subVectors(bTip, bBase);
|
|
8791
9687
|
if (dirA.lengthSq() < 1e-12 || dirB.lengthSq() < 1e-12) return null;
|
|
8792
9688
|
return clamp01((1 - dirA.normalize().dot(dirB.normalize())) / 0.45);
|
|
8793
9689
|
}
|
|
@@ -8797,18 +9693,18 @@ function computePalmPose(joints, handedness) {
|
|
|
8797
9693
|
const indexBase = joints["index-finger-metacarpal"];
|
|
8798
9694
|
const pinkyBase = joints["pinky-finger-metacarpal"];
|
|
8799
9695
|
if (!wrist || !indexBase || !pinkyBase) return null;
|
|
8800
|
-
const u = new
|
|
8801
|
-
const v = new
|
|
8802
|
-
const normal = new
|
|
9696
|
+
const u = new THREE26.Vector3().subVectors(indexBase, wrist);
|
|
9697
|
+
const v = new THREE26.Vector3().subVectors(pinkyBase, wrist);
|
|
9698
|
+
const normal = new THREE26.Vector3().crossVectors(u, v);
|
|
8803
9699
|
if (normal.lengthSq() < 1e-12) return null;
|
|
8804
9700
|
normal.normalize();
|
|
8805
9701
|
if (handedness === "left") normal.multiplyScalar(-1);
|
|
8806
|
-
const right = new
|
|
9702
|
+
const right = new THREE26.Vector3().subVectors(indexBase, pinkyBase);
|
|
8807
9703
|
if (right.lengthSq() < 1e-12) return null;
|
|
8808
9704
|
right.normalize();
|
|
8809
9705
|
if (handedness === "left") right.multiplyScalar(-1);
|
|
8810
|
-
const up = new
|
|
8811
|
-
const center = new
|
|
9706
|
+
const up = new THREE26.Vector3().crossVectors(normal, right).normalize();
|
|
9707
|
+
const center = new THREE26.Vector3().add(wrist).add(indexBase).add(pinkyBase).divideScalar(3);
|
|
8812
9708
|
return {
|
|
8813
9709
|
center,
|
|
8814
9710
|
normal,
|
|
@@ -8820,17 +9716,17 @@ function computePalmPose(joints, handedness) {
|
|
|
8820
9716
|
__name(computePalmPose, "computePalmPose");
|
|
8821
9717
|
function computeHandShape(joints, handedness) {
|
|
8822
9718
|
const fingers = {};
|
|
8823
|
-
let
|
|
9719
|
+
let tracked2 = 0;
|
|
8824
9720
|
for (const finger of XR_FINGERS) {
|
|
8825
9721
|
const curl = computeFingerCurl(joints, finger);
|
|
8826
9722
|
if (curl) {
|
|
8827
9723
|
fingers[finger] = curl;
|
|
8828
|
-
|
|
9724
|
+
tracked2 += 1;
|
|
8829
9725
|
} else {
|
|
8830
9726
|
fingers[finger] = { baseCurl: 0, tipCurl: 0, curl: 0 };
|
|
8831
9727
|
}
|
|
8832
9728
|
}
|
|
8833
|
-
if (
|
|
9729
|
+
if (tracked2 === 0) return null;
|
|
8834
9730
|
const pinch = {};
|
|
8835
9731
|
for (const finger of PINCH_FINGERS) {
|
|
8836
9732
|
pinch[finger] = computePinch(joints, finger) ?? 0;
|
|
@@ -8839,7 +9735,7 @@ function computeHandShape(joints, handedness) {
|
|
|
8839
9735
|
const thumbTip = joints["thumb-tip"];
|
|
8840
9736
|
let thumbDirection = null;
|
|
8841
9737
|
if (thumbBase && thumbTip) {
|
|
8842
|
-
const direction = new
|
|
9738
|
+
const direction = new THREE26.Vector3().subVectors(thumbTip, thumbBase);
|
|
8843
9739
|
if (direction.lengthSq() > 1e-12) thumbDirection = direction.normalize();
|
|
8844
9740
|
}
|
|
8845
9741
|
const fingerDirections = {};
|
|
@@ -8850,7 +9746,7 @@ function computeHandShape(joints, handedness) {
|
|
|
8850
9746
|
fingerDirections[finger] = null;
|
|
8851
9747
|
continue;
|
|
8852
9748
|
}
|
|
8853
|
-
const direction = new
|
|
9749
|
+
const direction = new THREE26.Vector3().subVectors(tip, base);
|
|
8854
9750
|
fingerDirections[finger] = direction.lengthSq() > 1e-12 ? direction.normalize() : null;
|
|
8855
9751
|
}
|
|
8856
9752
|
return {
|
|
@@ -8884,12 +9780,12 @@ function scoreAgainst(actual, target, tolerance) {
|
|
|
8884
9780
|
__name(scoreAgainst, "scoreAgainst");
|
|
8885
9781
|
var DEFAULT_DIRECTION_TOLERANCE = 45;
|
|
8886
9782
|
var WORLD_DIRECTIONS = {
|
|
8887
|
-
up: new
|
|
8888
|
-
down: new
|
|
8889
|
-
forward: new
|
|
8890
|
-
back: new
|
|
8891
|
-
left: new
|
|
8892
|
-
right: new
|
|
9783
|
+
up: new THREE26.Vector3(0, 1, 0),
|
|
9784
|
+
down: new THREE26.Vector3(0, -1, 0),
|
|
9785
|
+
forward: new THREE26.Vector3(0, 0, -1),
|
|
9786
|
+
back: new THREE26.Vector3(0, 0, 1),
|
|
9787
|
+
left: new THREE26.Vector3(-1, 0, 0),
|
|
9788
|
+
right: new THREE26.Vector3(1, 0, 0)
|
|
8893
9789
|
};
|
|
8894
9790
|
function axisVector(shape, axis) {
|
|
8895
9791
|
if (axis === "thumb") return shape.thumbDirection;
|
|
@@ -8904,7 +9800,7 @@ function resolveDirection(direction, shape, context) {
|
|
|
8904
9800
|
const head = context?.headPosition;
|
|
8905
9801
|
const origin = shape.palm?.center;
|
|
8906
9802
|
if (!head || !origin) return null;
|
|
8907
|
-
const toHead = new
|
|
9803
|
+
const toHead = new THREE26.Vector3().subVectors(head, origin);
|
|
8908
9804
|
if (toHead.lengthSq() < 1e-12) return null;
|
|
8909
9805
|
toHead.normalize();
|
|
8910
9806
|
return direction === "toward-head" ? toHead : toHead.multiplyScalar(-1);
|
|
@@ -8916,8 +9812,8 @@ function scoreDirections(actual, accepted, shape, toleranceDegrees, context) {
|
|
|
8916
9812
|
for (const direction of accepted) {
|
|
8917
9813
|
const wanted = resolveDirection(direction, shape, context);
|
|
8918
9814
|
if (!wanted) continue;
|
|
8919
|
-
const angle =
|
|
8920
|
-
Math.acos(
|
|
9815
|
+
const angle = THREE26.MathUtils.radToDeg(
|
|
9816
|
+
Math.acos(THREE26.MathUtils.clamp(actual.dot(wanted), -1, 1))
|
|
8921
9817
|
);
|
|
8922
9818
|
const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
|
|
8923
9819
|
const score = clamp01(1 - normalizedError / MATCH_FALLOFF);
|
|
@@ -8982,8 +9878,8 @@ function matchHandPose(shape, definition, context) {
|
|
|
8982
9878
|
if (!handAxis || !wanted) {
|
|
8983
9879
|
consider(0, "orientation");
|
|
8984
9880
|
} else {
|
|
8985
|
-
const angle =
|
|
8986
|
-
Math.acos(
|
|
9881
|
+
const angle = THREE26.MathUtils.radToDeg(
|
|
9882
|
+
Math.acos(THREE26.MathUtils.clamp(handAxis.dot(wanted), -1, 1))
|
|
8987
9883
|
);
|
|
8988
9884
|
const normalizedError = Math.max(0, angle - toleranceDegrees) / 90;
|
|
8989
9885
|
consider(clamp01(1 - normalizedError / MATCH_FALLOFF), "orientation");
|
|
@@ -9061,7 +9957,7 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
|
|
|
9061
9957
|
this.trackers = /* @__PURE__ */ new Map();
|
|
9062
9958
|
this.shapes = /* @__PURE__ */ new Map();
|
|
9063
9959
|
/** Reused so head-relative orientation checks allocate nothing per frame. */
|
|
9064
|
-
this.headPosition = new
|
|
9960
|
+
this.headPosition = new THREE26.Vector3();
|
|
9065
9961
|
this.elapsed = 0;
|
|
9066
9962
|
this.warnedNoHands = false;
|
|
9067
9963
|
this.noHandSeconds = 0;
|
|
@@ -9077,8 +9973,8 @@ var _XRHandPoseSystem = class _XRHandPoseSystem {
|
|
|
9077
9973
|
const entries = this.collectEntries(world);
|
|
9078
9974
|
if (entries.length === 0) return;
|
|
9079
9975
|
if (!this.warnedNoHands) {
|
|
9080
|
-
const
|
|
9081
|
-
if (
|
|
9976
|
+
const tracked2 = this.shapes.get("left") !== null || this.shapes.get("right") !== null;
|
|
9977
|
+
if (tracked2) {
|
|
9082
9978
|
this.warnedNoHands = true;
|
|
9083
9979
|
} else {
|
|
9084
9980
|
this.noHandSeconds += deltaTime;
|
|
@@ -9224,6 +10120,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9224
10120
|
const interactable = world.getComponent(entityId, XRInteractableComponent);
|
|
9225
10121
|
if (!interactable?.enabled) continue;
|
|
9226
10122
|
if (interactable.hoverBehavior === "none") continue;
|
|
10123
|
+
if (isUiWidget(world, entityId)) continue;
|
|
9227
10124
|
this.begin(world, entityId, interactable);
|
|
9228
10125
|
}
|
|
9229
10126
|
for (const [entityId, record] of this.records) {
|
|
@@ -9244,7 +10141,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9244
10141
|
const wantsColor = interactable.hoverBehavior === "color" || interactable.hoverBehavior === "both";
|
|
9245
10142
|
this.records.set(entityId, {
|
|
9246
10143
|
shell: wantsColor ? this.addShell(world, entityId, interactable) : null,
|
|
9247
|
-
baseScale: new
|
|
10144
|
+
baseScale: new THREE26.Vector3(
|
|
9248
10145
|
transform.scale.x,
|
|
9249
10146
|
transform.scale.y,
|
|
9250
10147
|
transform.scale.z
|
|
@@ -9257,27 +10154,27 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9257
10154
|
addShell(world, entityId, interactable) {
|
|
9258
10155
|
const object = world.getComponent(entityId, Object3DRef)?.object;
|
|
9259
10156
|
if (!object) return null;
|
|
9260
|
-
const material = new
|
|
9261
|
-
color: new
|
|
10157
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
10158
|
+
color: new THREE26.Color(interactable.hoverColor),
|
|
9262
10159
|
// Back faces only, so the shell shows just outside the silhouette instead
|
|
9263
10160
|
// of covering the object.
|
|
9264
|
-
side:
|
|
10161
|
+
side: THREE26.BackSide,
|
|
9265
10162
|
transparent: true,
|
|
9266
10163
|
opacity: 0.85,
|
|
9267
10164
|
depthWrite: false
|
|
9268
10165
|
});
|
|
9269
|
-
const group = new
|
|
10166
|
+
const group = new THREE26.Group();
|
|
9270
10167
|
group.name = "XRHoverShell";
|
|
9271
10168
|
group.userData[XR_HOVER_SHELL_FLAG] = true;
|
|
9272
10169
|
group.renderOrder = 998;
|
|
9273
10170
|
object.traverse((child) => {
|
|
9274
|
-
if (!(child instanceof
|
|
10171
|
+
if (!(child instanceof THREE26.Mesh) || !child.geometry) return;
|
|
9275
10172
|
if (child.userData[XR_HOVER_SHELL_FLAG]) return;
|
|
9276
|
-
const clone = new
|
|
10173
|
+
const clone = new THREE26.Mesh(child.geometry, material);
|
|
9277
10174
|
child.updateWorldMatrix(true, false);
|
|
9278
10175
|
object.updateWorldMatrix(true, false);
|
|
9279
10176
|
clone.matrixAutoUpdate = false;
|
|
9280
|
-
clone.matrix.copy(object.matrixWorld).invert().multiply(child.matrixWorld).scale(new
|
|
10177
|
+
clone.matrix.copy(object.matrixWorld).invert().multiply(child.matrixWorld).scale(new THREE26.Vector3(SHELL_INFLATE, SHELL_INFLATE, SHELL_INFLATE));
|
|
9281
10178
|
clone.userData[XR_HOVER_SHELL_FLAG] = true;
|
|
9282
10179
|
clone.raycast = () => {
|
|
9283
10180
|
};
|
|
@@ -9326,7 +10223,7 @@ var _XRHoverVisualSystem = class _XRHoverVisualSystem {
|
|
|
9326
10223
|
if (!shell) return;
|
|
9327
10224
|
shell.parent?.remove(shell);
|
|
9328
10225
|
shell.traverse((child) => {
|
|
9329
|
-
if (child instanceof
|
|
10226
|
+
if (child instanceof THREE26.Mesh) {
|
|
9330
10227
|
const material = child.material;
|
|
9331
10228
|
if (Array.isArray(material)) {
|
|
9332
10229
|
for (const entry of material) entry.dispose();
|
|
@@ -9352,5 +10249,5 @@ __name(_XRHoverVisualSystem, "XRHoverVisualSystem");
|
|
|
9352
10249
|
var XRHoverVisualSystem = _XRHoverVisualSystem;
|
|
9353
10250
|
|
|
9354
10251
|
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-
|
|
10252
|
+
//# sourceMappingURL=chunk-VYIWOXAY.js.map
|
|
10253
|
+
//# sourceMappingURL=chunk-VYIWOXAY.js.map
|