@liveroom-tech/react-immersive 2.2.1 → 3.0.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/README.md +193 -28
- package/dist/index.d.mts +386 -76
- package/dist/index.d.ts +386 -76
- package/dist/index.js +1769 -468
- package/dist/index.mjs +1589 -288
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,13 +48,17 @@ var init_bvhWorkerCode = __esm({
|
|
|
48
48
|
var index_exports = {};
|
|
49
49
|
__export(index_exports, {
|
|
50
50
|
BindingBuilder: () => BindingBuilder,
|
|
51
|
+
DEFAULT_SCENE_CONFIG: () => DEFAULT_SCENE_CONFIG,
|
|
51
52
|
MATERIAL_BLENDING_MODES: () => MATERIAL_BLENDING_MODES,
|
|
52
53
|
MATERIAL_SIDES: () => MATERIAL_SIDES,
|
|
53
54
|
ModelViewer: () => ModelViewer,
|
|
54
55
|
SimpleModelViewer: () => SimpleModelViewer,
|
|
56
|
+
defineObjectBindings: () => defineObjectBindings,
|
|
55
57
|
material: () => material,
|
|
56
58
|
patchBindings: () => patchBindings,
|
|
57
59
|
patchSceneConfig: () => patchSceneConfig,
|
|
60
|
+
selectBindingKeys: () => selectBindingKeys,
|
|
61
|
+
selectBindings: () => selectBindings,
|
|
58
62
|
useObjectBinding: () => useObjectBinding,
|
|
59
63
|
useObjectBindingIds: () => useObjectBindingIds,
|
|
60
64
|
useObjectBindings: () => useObjectBindings,
|
|
@@ -63,6 +67,8 @@ __export(index_exports, {
|
|
|
63
67
|
useViewerActions: () => useViewerActions,
|
|
64
68
|
useViewerAnimations: () => useViewerAnimations,
|
|
65
69
|
useViewerCamera: () => useViewerCamera,
|
|
70
|
+
useViewerConnection: () => useViewerConnection,
|
|
71
|
+
useViewerEffects: () => useViewerEffects,
|
|
66
72
|
useViewerHover: () => useViewerHover,
|
|
67
73
|
useViewerModel: () => useViewerModel,
|
|
68
74
|
useViewerSelection: () => useViewerSelection
|
|
@@ -221,7 +227,7 @@ function disposeSceneBVH(root) {
|
|
|
221
227
|
var import_fiber12 = require("@react-three/fiber");
|
|
222
228
|
var import_xr4 = require("@react-three/xr");
|
|
223
229
|
var import_qrcode = require("qrcode.react");
|
|
224
|
-
var
|
|
230
|
+
var import_three21 = require("three");
|
|
225
231
|
|
|
226
232
|
// #style-inject:#style-inject
|
|
227
233
|
function styleInject(css, { insertAt } = {}) {
|
|
@@ -2063,6 +2069,26 @@ function Controls({ controlsRef, onCameraChange }) {
|
|
|
2063
2069
|
// src/components/Lights.tsx
|
|
2064
2070
|
var import_react9 = require("react");
|
|
2065
2071
|
var import_fiber5 = require("@react-three/fiber");
|
|
2072
|
+
var import_three10 = require("three");
|
|
2073
|
+
|
|
2074
|
+
// src/utils/resolveBindingKey.ts
|
|
2075
|
+
function resolveBindingKey(objectBindings, objectId) {
|
|
2076
|
+
if (objectBindings[objectId]) {
|
|
2077
|
+
return objectId;
|
|
2078
|
+
}
|
|
2079
|
+
const idMatch = Object.entries(objectBindings).find(
|
|
2080
|
+
([, binding]) => binding.id === objectId
|
|
2081
|
+
)?.[0];
|
|
2082
|
+
if (idMatch) {
|
|
2083
|
+
return idMatch;
|
|
2084
|
+
}
|
|
2085
|
+
const modelObjectMatch = Object.entries(objectBindings).find(
|
|
2086
|
+
([, binding]) => binding.modelObjectId === objectId
|
|
2087
|
+
)?.[0];
|
|
2088
|
+
return modelObjectMatch ?? null;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// src/components/Lights.tsx
|
|
2066
2092
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2067
2093
|
function rotatePositionY(pos, deg) {
|
|
2068
2094
|
if (!deg) return pos;
|
|
@@ -2142,21 +2168,42 @@ function LightInstance({
|
|
|
2142
2168
|
shadows,
|
|
2143
2169
|
shadowsEnabled,
|
|
2144
2170
|
environmentRotation,
|
|
2145
|
-
modelBounds
|
|
2171
|
+
modelBounds,
|
|
2172
|
+
objectBindings,
|
|
2173
|
+
nodeRefs
|
|
2146
2174
|
}) {
|
|
2147
2175
|
const dirRef = (0, import_react9.useRef)(null);
|
|
2148
2176
|
const pointRef = (0, import_react9.useRef)(null);
|
|
2149
2177
|
const spotRef = (0, import_react9.useRef)(null);
|
|
2150
2178
|
const camera = (0, import_fiber5.useThree)((s) => s.camera);
|
|
2179
|
+
const rootScene = (0, import_fiber5.useThree)((s) => s.scene);
|
|
2180
|
+
const attachedPosition = (0, import_react9.useMemo)(() => new import_three10.Vector3(), []);
|
|
2151
2181
|
const position = (0, import_react9.useMemo)(
|
|
2152
|
-
() => light.attachedToCamera ? light.position : rotatePositionY(light.position, environmentRotation),
|
|
2153
|
-
[
|
|
2182
|
+
() => light.attachedToCamera || light.attachment ? light.position : rotatePositionY(light.position, environmentRotation),
|
|
2183
|
+
[
|
|
2184
|
+
light.position,
|
|
2185
|
+
light.attachedToCamera,
|
|
2186
|
+
light.attachment,
|
|
2187
|
+
environmentRotation
|
|
2188
|
+
]
|
|
2154
2189
|
);
|
|
2155
2190
|
(0, import_fiber5.useFrame)(() => {
|
|
2156
|
-
|
|
2157
|
-
if (
|
|
2158
|
-
if (
|
|
2159
|
-
|
|
2191
|
+
const instance = dirRef.current ?? pointRef.current ?? spotRef.current;
|
|
2192
|
+
if (!instance) return;
|
|
2193
|
+
if (light.attachedToCamera) {
|
|
2194
|
+
instance.position.copy(camera.position);
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
const attachment = light.attachment;
|
|
2198
|
+
if (!attachment) return;
|
|
2199
|
+
const bindingKey = objectBindings ? resolveBindingKey(objectBindings, attachment.objectId) : null;
|
|
2200
|
+
const binding = bindingKey ? objectBindings?.[bindingKey] : void 0;
|
|
2201
|
+
const modelObjectId = binding?.modelObjectId ?? attachment.objectId;
|
|
2202
|
+
const target = (bindingKey ? nodeRefs?.current[bindingKey] : void 0) ?? rootScene.getObjectByName(modelObjectId);
|
|
2203
|
+
if (!target) return;
|
|
2204
|
+
attachedPosition.fromArray(attachment.offset);
|
|
2205
|
+
target.localToWorld(attachedPosition);
|
|
2206
|
+
instance.position.copy(attachedPosition);
|
|
2160
2207
|
});
|
|
2161
2208
|
const castShadow = shadowsEnabled && shadows.enabled && light.castShadow;
|
|
2162
2209
|
const fit = (0, import_react9.useMemo)(
|
|
@@ -2202,6 +2249,8 @@ function LightInstance({
|
|
|
2202
2249
|
color: light.color,
|
|
2203
2250
|
intensity: light.intensity,
|
|
2204
2251
|
position,
|
|
2252
|
+
distance: light.distance,
|
|
2253
|
+
decay: light.decay,
|
|
2205
2254
|
castShadow,
|
|
2206
2255
|
"shadow-mapSize-width": shadows.mapSize,
|
|
2207
2256
|
"shadow-mapSize-height": shadows.mapSize,
|
|
@@ -2227,7 +2276,9 @@ function Lights({
|
|
|
2227
2276
|
shadowsEnabled = true,
|
|
2228
2277
|
environmentRotation = 0,
|
|
2229
2278
|
environmentConfig,
|
|
2230
|
-
modelBounds
|
|
2279
|
+
modelBounds,
|
|
2280
|
+
objectBindings,
|
|
2281
|
+
nodeRefs
|
|
2231
2282
|
}) {
|
|
2232
2283
|
const lighting = lightingConfig ?? DEFAULT_LIGHTING;
|
|
2233
2284
|
const shadows = shadowConfig ?? DEFAULT_SHADOWS;
|
|
@@ -2248,7 +2299,9 @@ function Lights({
|
|
|
2248
2299
|
shadows,
|
|
2249
2300
|
shadowsEnabled,
|
|
2250
2301
|
environmentRotation,
|
|
2251
|
-
modelBounds
|
|
2302
|
+
modelBounds,
|
|
2303
|
+
objectBindings,
|
|
2304
|
+
nodeRefs
|
|
2252
2305
|
},
|
|
2253
2306
|
light.id
|
|
2254
2307
|
)),
|
|
@@ -2269,7 +2322,9 @@ function Lights({
|
|
|
2269
2322
|
shadows,
|
|
2270
2323
|
shadowsEnabled,
|
|
2271
2324
|
environmentRotation: 0,
|
|
2272
|
-
modelBounds
|
|
2325
|
+
modelBounds,
|
|
2326
|
+
objectBindings,
|
|
2327
|
+
nodeRefs
|
|
2273
2328
|
}
|
|
2274
2329
|
)
|
|
2275
2330
|
] });
|
|
@@ -2283,7 +2338,7 @@ var import_fiber7 = require("@react-three/fiber");
|
|
|
2283
2338
|
var import_drei3 = require("@react-three/drei");
|
|
2284
2339
|
var import_fiber6 = require("@react-three/fiber");
|
|
2285
2340
|
var import_react10 = require("react");
|
|
2286
|
-
var
|
|
2341
|
+
var import_three11 = require("three");
|
|
2287
2342
|
var import_three_stdlib2 = require("three-stdlib");
|
|
2288
2343
|
function createUnlitEmissiveTexturePlugin(parser) {
|
|
2289
2344
|
return {
|
|
@@ -2309,7 +2364,7 @@ function createUnlitEmissiveTexturePlugin(parser) {
|
|
|
2309
2364
|
[...wanted].map(async ([name, index]) => {
|
|
2310
2365
|
const texture = await parser.getDependency("texture", index);
|
|
2311
2366
|
if (texture) {
|
|
2312
|
-
texture.colorSpace =
|
|
2367
|
+
texture.colorSpace = import_three11.SRGBColorSpace;
|
|
2313
2368
|
textureByName.set(name, texture);
|
|
2314
2369
|
}
|
|
2315
2370
|
})
|
|
@@ -2367,7 +2422,7 @@ function useConfiguredGLTF(url, config = {}) {
|
|
|
2367
2422
|
}
|
|
2368
2423
|
|
|
2369
2424
|
// src/components/Model.tsx
|
|
2370
|
-
var
|
|
2425
|
+
var import_three15 = require("three");
|
|
2371
2426
|
var import_three_stdlib3 = require("three-stdlib");
|
|
2372
2427
|
|
|
2373
2428
|
// src/utils/animationClips.ts
|
|
@@ -2387,7 +2442,7 @@ function resolveAnimationClips(clips) {
|
|
|
2387
2442
|
}
|
|
2388
2443
|
|
|
2389
2444
|
// src/components/model/materialUtils.ts
|
|
2390
|
-
var
|
|
2445
|
+
var import_three12 = require("three");
|
|
2391
2446
|
function isMeshStandardMaterial(material2) {
|
|
2392
2447
|
return Boolean(
|
|
2393
2448
|
material2 && typeof material2 === "object" && "clone" in material2 && "color" in material2 && "metalness" in material2 && "roughness" in material2
|
|
@@ -2429,28 +2484,28 @@ var SRGB_TEXTURE_KEYS = /* @__PURE__ */ new Set([
|
|
|
2429
2484
|
"specularColorMap"
|
|
2430
2485
|
]);
|
|
2431
2486
|
function colorSpaceForTextureKey(key) {
|
|
2432
|
-
return SRGB_TEXTURE_KEYS.has(key) ?
|
|
2487
|
+
return SRGB_TEXTURE_KEYS.has(key) ? import_three12.SRGBColorSpace : import_three12.NoColorSpace;
|
|
2433
2488
|
}
|
|
2434
2489
|
function getMaterialTexturePath(material2, key) {
|
|
2435
2490
|
return material2?.[key]?.path;
|
|
2436
2491
|
}
|
|
2437
2492
|
function sideFromConfig(side) {
|
|
2438
|
-
if (side === "back") return
|
|
2439
|
-
if (side === "double") return
|
|
2440
|
-
return
|
|
2493
|
+
if (side === "back") return import_three12.BackSide;
|
|
2494
|
+
if (side === "double") return import_three12.DoubleSide;
|
|
2495
|
+
return import_three12.FrontSide;
|
|
2441
2496
|
}
|
|
2442
2497
|
function blendingFromConfig(blendingMode) {
|
|
2443
|
-
if (blendingMode === "additive") return
|
|
2444
|
-
return
|
|
2498
|
+
if (blendingMode === "additive") return import_three12.AdditiveBlending;
|
|
2499
|
+
return import_three12.NormalBlending;
|
|
2445
2500
|
}
|
|
2446
2501
|
function toSafeVector2(value, fallbackX = 1, fallbackY = fallbackX) {
|
|
2447
2502
|
if (value && typeof value === "object") {
|
|
2448
2503
|
const vectorLike = value;
|
|
2449
2504
|
if (typeof vectorLike.x === "number" && Number.isFinite(vectorLike.x) && typeof vectorLike.y === "number" && Number.isFinite(vectorLike.y)) {
|
|
2450
|
-
return new
|
|
2505
|
+
return new import_three12.Vector2(vectorLike.x, vectorLike.y);
|
|
2451
2506
|
}
|
|
2452
2507
|
}
|
|
2453
|
-
return new
|
|
2508
|
+
return new import_three12.Vector2(fallbackX, fallbackY);
|
|
2454
2509
|
}
|
|
2455
2510
|
function clampAnimationSpeed(speed) {
|
|
2456
2511
|
return Number.isFinite(speed) && speed > 0 ? speed : 1;
|
|
@@ -2465,12 +2520,12 @@ function getClipLoopMode(clipConfig) {
|
|
|
2465
2520
|
}
|
|
2466
2521
|
|
|
2467
2522
|
// src/components/model/materialFactory.ts
|
|
2468
|
-
var
|
|
2523
|
+
var import_three13 = require("three");
|
|
2469
2524
|
function toStandardMaterial(material2) {
|
|
2470
2525
|
if (isMeshStandardMaterial(material2)) return material2;
|
|
2471
2526
|
if (!material2 || typeof material2 !== "object") return null;
|
|
2472
2527
|
const src = material2;
|
|
2473
|
-
const std = new
|
|
2528
|
+
const std = new import_three13.MeshStandardMaterial();
|
|
2474
2529
|
if (typeof src.name === "string") std.name = src.name;
|
|
2475
2530
|
std.metalness = 0;
|
|
2476
2531
|
std.roughness = 1;
|
|
@@ -2478,17 +2533,17 @@ function toStandardMaterial(material2) {
|
|
|
2478
2533
|
if (isUnlit) {
|
|
2479
2534
|
std.color.set(0);
|
|
2480
2535
|
std.emissiveIntensity = 1;
|
|
2481
|
-
if (src.map instanceof
|
|
2536
|
+
if (src.map instanceof import_three13.Texture) {
|
|
2482
2537
|
std.emissiveMap = src.map;
|
|
2483
2538
|
std.emissive.set(16777215);
|
|
2484
|
-
} else if (src.color instanceof
|
|
2539
|
+
} else if (src.color instanceof import_three13.Color) {
|
|
2485
2540
|
std.emissive.copy(src.color);
|
|
2486
2541
|
}
|
|
2487
2542
|
} else {
|
|
2488
|
-
if (src.color instanceof
|
|
2489
|
-
if (src.map instanceof
|
|
2490
|
-
if (src.emissive instanceof
|
|
2491
|
-
if (src.emissiveMap instanceof
|
|
2543
|
+
if (src.color instanceof import_three13.Color) std.color.copy(src.color);
|
|
2544
|
+
if (src.map instanceof import_three13.Texture) std.map = src.map;
|
|
2545
|
+
if (src.emissive instanceof import_three13.Color) std.emissive.copy(src.emissive);
|
|
2546
|
+
if (src.emissiveMap instanceof import_three13.Texture) std.emissiveMap = src.emissiveMap;
|
|
2492
2547
|
}
|
|
2493
2548
|
const shared = [
|
|
2494
2549
|
"aoMap",
|
|
@@ -2520,7 +2575,7 @@ function createPhysicalMaterialFromStandard(original) {
|
|
|
2520
2575
|
if (isMeshPhysicalMaterial(original)) {
|
|
2521
2576
|
return original.clone();
|
|
2522
2577
|
}
|
|
2523
|
-
const cloned = new
|
|
2578
|
+
const cloned = new import_three13.MeshPhysicalMaterial();
|
|
2524
2579
|
cloned.name = original.name;
|
|
2525
2580
|
cloned.color.copy(original.color);
|
|
2526
2581
|
cloned.map = original.map;
|
|
@@ -2649,7 +2704,7 @@ function snapshotBaseMaterial(cloned) {
|
|
|
2649
2704
|
}
|
|
2650
2705
|
|
|
2651
2706
|
// src/components/model/applyMaterialConfig.ts
|
|
2652
|
-
var
|
|
2707
|
+
var import_three14 = require("three");
|
|
2653
2708
|
function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
2654
2709
|
material2.map = material2.userData.baseMap ?? null;
|
|
2655
2710
|
material2.color.copy(material2.userData.baseColor);
|
|
@@ -2657,7 +2712,7 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2657
2712
|
material2.metalnessMap = material2.userData.baseMetalnessMap ?? null;
|
|
2658
2713
|
material2.roughness = material2.userData.baseRoughness ?? material2.roughness;
|
|
2659
2714
|
material2.roughnessMap = material2.userData.baseRoughnessMap ?? null;
|
|
2660
|
-
material2.emissive.copy(material2.userData.baseEmissive ?? new
|
|
2715
|
+
material2.emissive.copy(material2.userData.baseEmissive ?? new import_three14.Color(0, 0, 0));
|
|
2661
2716
|
material2.emissiveIntensity = material2.userData.baseEmissiveIntensity ?? material2.emissiveIntensity;
|
|
2662
2717
|
material2.emissiveMap = material2.userData.baseEmissiveMap ?? null;
|
|
2663
2718
|
material2.opacity = material2.userData.baseOpacity ?? 1;
|
|
@@ -2666,9 +2721,9 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2666
2721
|
material2.alphaTest = material2.userData.baseAlphaTest ?? 0;
|
|
2667
2722
|
material2.alphaHash = material2.userData.baseAlphaHash ?? false;
|
|
2668
2723
|
material2.dithering = material2.userData.baseDithering ?? false;
|
|
2669
|
-
material2.blending = material2.userData.baseBlending ??
|
|
2724
|
+
material2.blending = material2.userData.baseBlending ?? import_three14.NormalBlending;
|
|
2670
2725
|
material2.depthWrite = material2.userData.baseDepthWrite ?? true;
|
|
2671
|
-
material2.side = material2.userData.baseSide ??
|
|
2726
|
+
material2.side = material2.userData.baseSide ?? import_three14.FrontSide;
|
|
2672
2727
|
material2.normalMap = material2.userData.baseNormalMap ?? null;
|
|
2673
2728
|
material2.normalScale.copy(toSafeVector2(material2.userData.baseNormalScale));
|
|
2674
2729
|
material2.bumpMap = material2.userData.baseBumpMap ?? null;
|
|
@@ -2688,7 +2743,7 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2688
2743
|
);
|
|
2689
2744
|
material2.sheen = material2.userData.baseSheen ?? material2.sheen;
|
|
2690
2745
|
material2.sheenColor.copy(
|
|
2691
|
-
material2.userData.baseSheenColor ?? new
|
|
2746
|
+
material2.userData.baseSheenColor ?? new import_three14.Color(0, 0, 0)
|
|
2692
2747
|
);
|
|
2693
2748
|
material2.sheenColorMap = material2.userData.baseSheenColorMap ?? null;
|
|
2694
2749
|
material2.sheenRoughness = material2.userData.baseSheenRoughness ?? material2.sheenRoughness;
|
|
@@ -2701,14 +2756,14 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2701
2756
|
material2.thickness = material2.userData.baseThickness ?? material2.thickness;
|
|
2702
2757
|
material2.thicknessMap = material2.userData.baseThicknessMap ?? null;
|
|
2703
2758
|
material2.attenuationColor.copy(
|
|
2704
|
-
material2.userData.baseAttenuationColor ?? new
|
|
2759
|
+
material2.userData.baseAttenuationColor ?? new import_three14.Color("#ffffff")
|
|
2705
2760
|
);
|
|
2706
2761
|
material2.attenuationDistance = material2.userData.baseAttenuationDistance ?? material2.attenuationDistance;
|
|
2707
2762
|
material2.reflectivity = material2.userData.baseReflectivity ?? material2.reflectivity;
|
|
2708
2763
|
material2.specularIntensity = material2.userData.baseSpecularIntensity ?? material2.specularIntensity;
|
|
2709
2764
|
material2.specularIntensityMap = material2.userData.baseSpecularIntensityMap ?? null;
|
|
2710
2765
|
material2.specularColor.copy(
|
|
2711
|
-
material2.userData.baseSpecularColor ?? new
|
|
2766
|
+
material2.userData.baseSpecularColor ?? new import_three14.Color("#ffffff")
|
|
2712
2767
|
);
|
|
2713
2768
|
material2.specularColorMap = material2.userData.baseSpecularColorMap ?? null;
|
|
2714
2769
|
material2.flatShading = material2.userData.baseFlatShading ?? material2.flatShading;
|
|
@@ -2775,7 +2830,7 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2775
2830
|
"specularColorMap"
|
|
2776
2831
|
);
|
|
2777
2832
|
if (texturePath) {
|
|
2778
|
-
material2.map = getOrCreateTexture(texturePath,
|
|
2833
|
+
material2.map = getOrCreateTexture(texturePath, import_three14.SRGBColorSpace);
|
|
2779
2834
|
material2.color.set(resolvedBaseColor ?? "#ffffff");
|
|
2780
2835
|
} else if (resolvedBaseColor) {
|
|
2781
2836
|
material2.map = null;
|
|
@@ -2802,7 +2857,7 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2802
2857
|
material2.emissiveIntensity = configuredMaterial.emissiveIntensity;
|
|
2803
2858
|
}
|
|
2804
2859
|
if (emissiveMapPath) {
|
|
2805
|
-
material2.emissiveMap = getOrCreateTexture(emissiveMapPath,
|
|
2860
|
+
material2.emissiveMap = getOrCreateTexture(emissiveMapPath, import_three14.SRGBColorSpace);
|
|
2806
2861
|
}
|
|
2807
2862
|
if (configuredMaterial?.opacity !== void 0) {
|
|
2808
2863
|
material2.opacity = configuredMaterial.opacity;
|
|
@@ -2890,7 +2945,7 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2890
2945
|
if (sheenColorMapPath) {
|
|
2891
2946
|
material2.sheenColorMap = getOrCreateTexture(
|
|
2892
2947
|
sheenColorMapPath,
|
|
2893
|
-
|
|
2948
|
+
import_three14.SRGBColorSpace
|
|
2894
2949
|
);
|
|
2895
2950
|
}
|
|
2896
2951
|
if (configuredMaterial?.sheenRoughness !== void 0) {
|
|
@@ -2943,10 +2998,10 @@ function applyMaterialConfig(material2, configuredMaterial, resolvedBaseColor) {
|
|
|
2943
2998
|
if (specularColorMapPath) {
|
|
2944
2999
|
material2.specularColorMap = getOrCreateTexture(
|
|
2945
3000
|
specularColorMapPath,
|
|
2946
|
-
|
|
3001
|
+
import_three14.SRGBColorSpace
|
|
2947
3002
|
);
|
|
2948
3003
|
}
|
|
2949
|
-
material2.transparent = material2.opacity < 1 || material2.transmission > 0 || material2.blending !==
|
|
3004
|
+
material2.transparent = material2.opacity < 1 || material2.transmission > 0 || material2.blending !== import_three14.NormalBlending || Boolean((alphaMapPath || material2.alphaMap) && material2.alphaTest <= 0);
|
|
2950
3005
|
if (!material2.transparent) {
|
|
2951
3006
|
material2.depthWrite = true;
|
|
2952
3007
|
}
|
|
@@ -2966,6 +3021,24 @@ function refreshSkinnedBounds(root) {
|
|
|
2966
3021
|
|
|
2967
3022
|
// src/components/Model.tsx
|
|
2968
3023
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
3024
|
+
function applyBindingTransform(node, transform, original) {
|
|
3025
|
+
if (!original) return;
|
|
3026
|
+
if (transform?.position) node.position.fromArray(transform.position);
|
|
3027
|
+
else node.position.copy(original.position);
|
|
3028
|
+
if (transform?.rotation) {
|
|
3029
|
+
node.rotation.set(
|
|
3030
|
+
transform.rotation[0],
|
|
3031
|
+
transform.rotation[1],
|
|
3032
|
+
transform.rotation[2],
|
|
3033
|
+
original.rotation.order
|
|
3034
|
+
);
|
|
3035
|
+
} else {
|
|
3036
|
+
node.rotation.copy(original.rotation);
|
|
3037
|
+
}
|
|
3038
|
+
if (transform?.scale) node.scale.fromArray(transform.scale);
|
|
3039
|
+
else node.scale.copy(original.scale);
|
|
3040
|
+
node.updateMatrix();
|
|
3041
|
+
}
|
|
2969
3042
|
function firstMaterial(node) {
|
|
2970
3043
|
const mat = node.material;
|
|
2971
3044
|
if (!mat) return void 0;
|
|
@@ -3019,19 +3092,30 @@ function Model({
|
|
|
3019
3092
|
});
|
|
3020
3093
|
return map;
|
|
3021
3094
|
}, [scene]);
|
|
3095
|
+
const originalNodeTransforms = (0, import_react11.useMemo)(() => {
|
|
3096
|
+
const transforms = /* @__PURE__ */ new WeakMap();
|
|
3097
|
+
scene.traverse((node) => {
|
|
3098
|
+
transforms.set(node, {
|
|
3099
|
+
position: node.position.clone(),
|
|
3100
|
+
rotation: node.rotation.clone(),
|
|
3101
|
+
scale: node.scale.clone()
|
|
3102
|
+
});
|
|
3103
|
+
});
|
|
3104
|
+
return transforms;
|
|
3105
|
+
}, [scene]);
|
|
3022
3106
|
const shellNodeNames = (0, import_react11.useMemo)(() => {
|
|
3023
3107
|
const shell = /* @__PURE__ */ new Set();
|
|
3024
|
-
const sceneBox = new
|
|
3108
|
+
const sceneBox = new import_three15.Box3();
|
|
3025
3109
|
const meshNodes = [];
|
|
3026
3110
|
for (const [name, node] of Object.entries(nodeMap)) {
|
|
3027
3111
|
if (!isMeshNode(node)) continue;
|
|
3028
|
-
const box = new
|
|
3112
|
+
const box = new import_three15.Box3().setFromObject(node);
|
|
3029
3113
|
if (box.isEmpty()) continue;
|
|
3030
3114
|
meshNodes.push({ name, box });
|
|
3031
3115
|
sceneBox.union(box);
|
|
3032
3116
|
}
|
|
3033
|
-
const sceneSize = sceneBox.getSize(new
|
|
3034
|
-
const size = new
|
|
3117
|
+
const sceneSize = sceneBox.getSize(new import_three15.Vector3());
|
|
3118
|
+
const size = new import_three15.Vector3();
|
|
3035
3119
|
for (const { name, box } of meshNodes) {
|
|
3036
3120
|
box.getSize(size);
|
|
3037
3121
|
const isShell = size.x > sceneSize.x * 0.7 && size.z > sceneSize.z * 0.7 && size.y > sceneSize.y * 0.4;
|
|
@@ -3071,6 +3155,43 @@ function Model({
|
|
|
3071
3155
|
).sort().join(""),
|
|
3072
3156
|
[objectBindings]
|
|
3073
3157
|
);
|
|
3158
|
+
const bindingTransformSignature = (0, import_react11.useMemo)(
|
|
3159
|
+
() => Object.entries(objectBindings).map(
|
|
3160
|
+
([nodeName, binding]) => JSON.stringify([
|
|
3161
|
+
nodeName,
|
|
3162
|
+
binding.modelObjectId ?? nodeName,
|
|
3163
|
+
binding.transform ?? null
|
|
3164
|
+
])
|
|
3165
|
+
).sort().join(""),
|
|
3166
|
+
[objectBindings]
|
|
3167
|
+
);
|
|
3168
|
+
const transformedNodesRef = (0, import_react11.useRef)(/* @__PURE__ */ new Set());
|
|
3169
|
+
(0, import_react11.useEffect)(() => {
|
|
3170
|
+
for (const node of transformedNodesRef.current) {
|
|
3171
|
+
applyBindingTransform(node, void 0, originalNodeTransforms.get(node));
|
|
3172
|
+
}
|
|
3173
|
+
const nextTransformedNodes = /* @__PURE__ */ new Set();
|
|
3174
|
+
for (const [nodeName, binding] of Object.entries(objectBindings)) {
|
|
3175
|
+
if (!binding.transform) continue;
|
|
3176
|
+
const node = nodeMap[binding.modelObjectId ?? nodeName];
|
|
3177
|
+
if (!node) continue;
|
|
3178
|
+
applyBindingTransform(
|
|
3179
|
+
node,
|
|
3180
|
+
binding.transform,
|
|
3181
|
+
originalNodeTransforms.get(node)
|
|
3182
|
+
);
|
|
3183
|
+
nextTransformedNodes.add(node);
|
|
3184
|
+
}
|
|
3185
|
+
transformedNodesRef.current = nextTransformedNodes;
|
|
3186
|
+
scene.updateMatrixWorld(true);
|
|
3187
|
+
invalidate();
|
|
3188
|
+
}, [
|
|
3189
|
+
scene,
|
|
3190
|
+
nodeMap,
|
|
3191
|
+
originalNodeTransforms,
|
|
3192
|
+
bindingTransformSignature,
|
|
3193
|
+
invalidate
|
|
3194
|
+
]);
|
|
3074
3195
|
const perNodeMaterials = (0, import_react11.useMemo)(() => {
|
|
3075
3196
|
const map = {};
|
|
3076
3197
|
for (const [nodeName, binding] of Object.entries(objectBindings)) {
|
|
@@ -3105,7 +3226,7 @@ function Model({
|
|
|
3105
3226
|
const map = {};
|
|
3106
3227
|
if (shadingMode !== "unlit") return map;
|
|
3107
3228
|
for (const [nodeName, material2] of Object.entries(perNodeMaterials)) {
|
|
3108
|
-
const basic = new
|
|
3229
|
+
const basic = new import_three15.MeshBasicMaterial();
|
|
3109
3230
|
basic.color.copy(material2.color);
|
|
3110
3231
|
basic.map = material2.map;
|
|
3111
3232
|
basic.alphaMap = material2.alphaMap;
|
|
@@ -3121,7 +3242,7 @@ function Model({
|
|
|
3121
3242
|
const map = {};
|
|
3122
3243
|
if (shadingMode !== "normals") return map;
|
|
3123
3244
|
for (const nodeName of Object.keys(perNodeMaterials)) {
|
|
3124
|
-
map[nodeName] = new
|
|
3245
|
+
map[nodeName] = new import_three15.MeshNormalMaterial();
|
|
3125
3246
|
}
|
|
3126
3247
|
return map;
|
|
3127
3248
|
}, [perNodeMaterials, shadingMode]);
|
|
@@ -3130,7 +3251,7 @@ function Model({
|
|
|
3130
3251
|
if (shadingMode !== "lit" || rendererMode !== "matcap") return map;
|
|
3131
3252
|
const matcapTexture = getMatcapTexture();
|
|
3132
3253
|
for (const [nodeName, material2] of Object.entries(perNodeMaterials)) {
|
|
3133
|
-
const matcap = new
|
|
3254
|
+
const matcap = new import_three15.MeshMatcapMaterial();
|
|
3134
3255
|
matcap.matcap = matcapTexture;
|
|
3135
3256
|
matcap.color.copy(material2.color);
|
|
3136
3257
|
matcap.alphaMap = material2.alphaMap;
|
|
@@ -3304,7 +3425,7 @@ function Model({
|
|
|
3304
3425
|
const sourceMaterials = Array.isArray(original) ? original : [original];
|
|
3305
3426
|
const hasUv0 = Boolean(object.geometry.getAttribute("uv"));
|
|
3306
3427
|
const diagnosticMaterials = sourceMaterials.map((source, index) => {
|
|
3307
|
-
const material2 = new
|
|
3428
|
+
const material2 = new import_three15.MeshBasicMaterial({
|
|
3308
3429
|
color: hasUv0 ? "#ffffff" : "#ff00ff",
|
|
3309
3430
|
map: hasUv0 ? checkerTexture : null,
|
|
3310
3431
|
side: source.side
|
|
@@ -3334,16 +3455,16 @@ function Model({
|
|
|
3334
3455
|
const glbNodeName = binding.modelObjectId ?? nodeName;
|
|
3335
3456
|
const node = nodeMap[glbNodeName];
|
|
3336
3457
|
if (!isMeshNode(node)) continue;
|
|
3337
|
-
const geometry = new
|
|
3458
|
+
const geometry = new import_three15.WireframeGeometry(
|
|
3338
3459
|
node.geometry
|
|
3339
3460
|
);
|
|
3340
|
-
const lineMaterial = new
|
|
3461
|
+
const lineMaterial = new import_three15.LineBasicMaterial({
|
|
3341
3462
|
color: wireframeColor,
|
|
3342
3463
|
transparent: true,
|
|
3343
3464
|
opacity: wireframeOpacity,
|
|
3344
3465
|
depthTest: false
|
|
3345
3466
|
});
|
|
3346
|
-
const line = new
|
|
3467
|
+
const line = new import_three15.LineSegments(geometry, lineMaterial);
|
|
3347
3468
|
line.renderOrder = 1;
|
|
3348
3469
|
node.add(line);
|
|
3349
3470
|
added.push({ node, line });
|
|
@@ -3395,7 +3516,7 @@ function Model({
|
|
|
3395
3516
|
const applyClipConfigToAction = (action, clipConfig) => {
|
|
3396
3517
|
const loopMode = getClipLoopMode(clipConfig);
|
|
3397
3518
|
action.setLoop(
|
|
3398
|
-
loopMode === "once" ?
|
|
3519
|
+
loopMode === "once" ? import_three15.LoopOnce : import_three15.LoopRepeat,
|
|
3399
3520
|
loopMode === "once" ? 1 : Infinity
|
|
3400
3521
|
);
|
|
3401
3522
|
action.clampWhenFinished = loopMode === "once";
|
|
@@ -3462,7 +3583,7 @@ function Model({
|
|
|
3462
3583
|
invalidate();
|
|
3463
3584
|
};
|
|
3464
3585
|
(0, import_react11.useEffect)(() => {
|
|
3465
|
-
const mixer = new
|
|
3586
|
+
const mixer = new import_three15.AnimationMixer(scene);
|
|
3466
3587
|
mixerRef.current = mixer;
|
|
3467
3588
|
const actions = {};
|
|
3468
3589
|
for (const { clip, sourceName } of resolvedAnimationClips) {
|
|
@@ -3553,17 +3674,17 @@ function Model({
|
|
|
3553
3674
|
(0, import_fiber7.useFrame)((_, delta) => {
|
|
3554
3675
|
if (!groupRef.current) return;
|
|
3555
3676
|
const rotation = groupRef.current.rotation;
|
|
3556
|
-
rotation.x =
|
|
3677
|
+
rotation.x = import_three15.MathUtils.lerp(
|
|
3557
3678
|
rotation.x,
|
|
3558
3679
|
targetRotation[0],
|
|
3559
3680
|
1 - Math.exp(-5 * delta)
|
|
3560
3681
|
);
|
|
3561
|
-
rotation.y =
|
|
3682
|
+
rotation.y = import_three15.MathUtils.lerp(
|
|
3562
3683
|
rotation.y,
|
|
3563
3684
|
targetRotation[1],
|
|
3564
3685
|
1 - Math.exp(-5 * delta)
|
|
3565
3686
|
);
|
|
3566
|
-
rotation.z =
|
|
3687
|
+
rotation.z = import_three15.MathUtils.lerp(
|
|
3567
3688
|
rotation.z,
|
|
3568
3689
|
targetRotation[2],
|
|
3569
3690
|
1 - Math.exp(-5 * delta)
|
|
@@ -3574,27 +3695,30 @@ function Model({
|
|
|
3574
3695
|
const explodePartsRef = (0, import_react11.useRef)([]);
|
|
3575
3696
|
const explodeStrengthRef = (0, import_react11.useRef)(0);
|
|
3576
3697
|
const currentExplodeRef = (0, import_react11.useRef)(0);
|
|
3577
|
-
const explodeTmp = (0, import_react11.useMemo)(() => new
|
|
3698
|
+
const explodeTmp = (0, import_react11.useMemo)(() => new import_three15.Vector3(), []);
|
|
3578
3699
|
(0, import_react11.useEffect)(() => {
|
|
3700
|
+
const bindingByNode = /* @__PURE__ */ new Map();
|
|
3701
|
+
for (const [nodeName, binding] of Object.entries(objectBindings)) {
|
|
3702
|
+
const node = nodeMap[binding.modelObjectId ?? nodeName];
|
|
3703
|
+
if (node) bindingByNode.set(node, binding);
|
|
3704
|
+
}
|
|
3579
3705
|
for (const part of explodePartsRef.current) {
|
|
3580
|
-
|
|
3706
|
+
applyBindingTransform(
|
|
3707
|
+
part.node,
|
|
3708
|
+
bindingByNode.get(part.node)?.transform,
|
|
3709
|
+
originalNodeTransforms.get(part.node)
|
|
3710
|
+
);
|
|
3581
3711
|
}
|
|
3582
3712
|
currentExplodeRef.current = 0;
|
|
3583
3713
|
scene.updateWorldMatrix(true, true);
|
|
3584
|
-
const sceneBox = new
|
|
3585
|
-
const modelCenter = sceneBox.getCenter(new
|
|
3586
|
-
const radius = sceneBox.getSize(new
|
|
3714
|
+
const sceneBox = new import_three15.Box3().setFromObject(scene);
|
|
3715
|
+
const modelCenter = sceneBox.getCenter(new import_three15.Vector3());
|
|
3716
|
+
const radius = sceneBox.getSize(new import_three15.Vector3()).length() * 0.5;
|
|
3587
3717
|
explodeStrengthRef.current = Number.isFinite(radius) ? radius : 0;
|
|
3588
|
-
const targets = [];
|
|
3589
|
-
const targetSet =
|
|
3590
|
-
for (const [nodeName, binding] of Object.entries(objectBindings)) {
|
|
3591
|
-
const node = nodeMap[binding.modelObjectId ?? nodeName];
|
|
3592
|
-
if (!node || targetSet.has(node)) continue;
|
|
3593
|
-
targetSet.add(node);
|
|
3594
|
-
targets.push(node);
|
|
3595
|
-
}
|
|
3718
|
+
const targets = [...bindingByNode.keys()];
|
|
3719
|
+
const targetSet = new Set(targets);
|
|
3596
3720
|
const parts = [];
|
|
3597
|
-
const partCenter = new
|
|
3721
|
+
const partCenter = new import_three15.Vector3();
|
|
3598
3722
|
for (const node of targets) {
|
|
3599
3723
|
if (!node.parent) continue;
|
|
3600
3724
|
let ancestor = node.parent;
|
|
@@ -3607,7 +3731,7 @@ function Model({
|
|
|
3607
3731
|
ancestor = ancestor.parent;
|
|
3608
3732
|
}
|
|
3609
3733
|
if (nested) continue;
|
|
3610
|
-
const box = new
|
|
3734
|
+
const box = new import_three15.Box3().setFromObject(node);
|
|
3611
3735
|
if (box.isEmpty()) continue;
|
|
3612
3736
|
box.getCenter(partCenter);
|
|
3613
3737
|
const worldDir = partCenter.clone().sub(modelCenter);
|
|
@@ -3616,14 +3740,21 @@ function Model({
|
|
|
3616
3740
|
parts.push({
|
|
3617
3741
|
node,
|
|
3618
3742
|
restLocalPos: node.position.clone(),
|
|
3619
|
-
restWorldPos: node.getWorldPosition(new
|
|
3743
|
+
restWorldPos: node.getWorldPosition(new import_three15.Vector3()),
|
|
3620
3744
|
worldDir,
|
|
3621
|
-
parentInverse: new
|
|
3745
|
+
parentInverse: new import_three15.Matrix4().copy(node.parent.matrixWorld).invert()
|
|
3622
3746
|
});
|
|
3623
3747
|
}
|
|
3624
3748
|
explodePartsRef.current = parts;
|
|
3625
3749
|
invalidate();
|
|
3626
|
-
}, [
|
|
3750
|
+
}, [
|
|
3751
|
+
scene,
|
|
3752
|
+
nodeMap,
|
|
3753
|
+
nodeBindingSignature,
|
|
3754
|
+
bindingTransformSignature,
|
|
3755
|
+
originalNodeTransforms,
|
|
3756
|
+
invalidate
|
|
3757
|
+
]);
|
|
3627
3758
|
(0, import_react11.useEffect)(() => {
|
|
3628
3759
|
invalidate();
|
|
3629
3760
|
}, [explodeFactor, invalidate]);
|
|
@@ -3636,7 +3767,7 @@ function Model({
|
|
|
3636
3767
|
if (current === target) return;
|
|
3637
3768
|
currentExplodeRef.current = target;
|
|
3638
3769
|
} else {
|
|
3639
|
-
currentExplodeRef.current =
|
|
3770
|
+
currentExplodeRef.current = import_three15.MathUtils.lerp(
|
|
3640
3771
|
current,
|
|
3641
3772
|
target,
|
|
3642
3773
|
1 - Math.exp(-6 * delta)
|
|
@@ -3709,7 +3840,7 @@ function Model({
|
|
|
3709
3840
|
var import_react12 = require("react");
|
|
3710
3841
|
var import_drei4 = require("@react-three/drei");
|
|
3711
3842
|
var import_fiber8 = require("@react-three/fiber");
|
|
3712
|
-
var
|
|
3843
|
+
var import_three16 = require("three");
|
|
3713
3844
|
|
|
3714
3845
|
// src/styles/AnnotationsLayer.css
|
|
3715
3846
|
styleInject(".ri-annotationMarker--hovered {\n transform: scale(1.08);\n box-shadow: 0 12px 28px rgba(15, 23, 42, 0.18);\n background: rgba(40, 40, 40, 0.92);\n}\n.ri-viewAnnotationHeader {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n.ri-viewAnnotationTitle {\n margin: 0;\n color: #e2e8f0;\n font-size: 14px;\n font-weight: 600;\n}\n");
|
|
@@ -3722,7 +3853,7 @@ function useCameraBiasedAnchor(annotation, worldPositionsRef) {
|
|
|
3722
3853
|
const scene = (0, import_fiber8.useThree)((state) => state.scene);
|
|
3723
3854
|
const anchorNodeRef = (0, import_react12.useRef)(null);
|
|
3724
3855
|
const baseLocalPosition = (0, import_react12.useMemo)(
|
|
3725
|
-
() => new
|
|
3856
|
+
() => new import_three16.Vector3(
|
|
3726
3857
|
...annotation.anchorLocalPosition ?? annotation.localPosition ?? annotation.worldPosition
|
|
3727
3858
|
),
|
|
3728
3859
|
[
|
|
@@ -3731,9 +3862,9 @@ function useCameraBiasedAnchor(annotation, worldPositionsRef) {
|
|
|
3731
3862
|
annotation.worldPosition
|
|
3732
3863
|
]
|
|
3733
3864
|
);
|
|
3734
|
-
const worldPosition = (0, import_react12.useMemo)(() => new
|
|
3735
|
-
const biasedWorldPosition = (0, import_react12.useMemo)(() => new
|
|
3736
|
-
const toCamera = (0, import_react12.useMemo)(() => new
|
|
3865
|
+
const worldPosition = (0, import_react12.useMemo)(() => new import_three16.Vector3(), []);
|
|
3866
|
+
const biasedWorldPosition = (0, import_react12.useMemo)(() => new import_three16.Vector3(), []);
|
|
3867
|
+
const toCamera = (0, import_react12.useMemo)(() => new import_three16.Vector3(), []);
|
|
3737
3868
|
(0, import_react12.useEffect)(() => {
|
|
3738
3869
|
anchorNodeRef.current = null;
|
|
3739
3870
|
}, [annotation.anchorNodeName]);
|
|
@@ -3756,7 +3887,7 @@ function useCameraBiasedAnchor(annotation, worldPositionsRef) {
|
|
|
3756
3887
|
if (worldPositionsRef) {
|
|
3757
3888
|
let stored = worldPositionsRef.current.get(annotation.id);
|
|
3758
3889
|
if (!stored) {
|
|
3759
|
-
stored = new
|
|
3890
|
+
stored = new import_three16.Vector3();
|
|
3760
3891
|
worldPositionsRef.current.set(annotation.id, stored);
|
|
3761
3892
|
}
|
|
3762
3893
|
stored.copy(worldPosition);
|
|
@@ -4105,17 +4236,17 @@ function AnnotationsLayer({
|
|
|
4105
4236
|
);
|
|
4106
4237
|
(0, import_fiber8.useFrame)((_, delta) => {
|
|
4107
4238
|
if (!groupRef.current) return;
|
|
4108
|
-
groupRef.current.rotation.x =
|
|
4239
|
+
groupRef.current.rotation.x = import_three16.MathUtils.lerp(
|
|
4109
4240
|
groupRef.current.rotation.x,
|
|
4110
4241
|
targetRotation[0],
|
|
4111
4242
|
1 - Math.exp(-5 * delta)
|
|
4112
4243
|
);
|
|
4113
|
-
groupRef.current.rotation.y =
|
|
4244
|
+
groupRef.current.rotation.y = import_three16.MathUtils.lerp(
|
|
4114
4245
|
groupRef.current.rotation.y,
|
|
4115
4246
|
targetRotation[1],
|
|
4116
4247
|
1 - Math.exp(-5 * delta)
|
|
4117
4248
|
);
|
|
4118
|
-
groupRef.current.rotation.z =
|
|
4249
|
+
groupRef.current.rotation.z = import_three16.MathUtils.lerp(
|
|
4119
4250
|
groupRef.current.rotation.z,
|
|
4120
4251
|
targetRotation[2],
|
|
4121
4252
|
1 - Math.exp(-5 * delta)
|
|
@@ -4154,7 +4285,7 @@ function AnnotationsLayer({
|
|
|
4154
4285
|
// src/components/ModelViewer/MeasurementLayer.tsx
|
|
4155
4286
|
var import_react13 = require("react");
|
|
4156
4287
|
var import_drei5 = require("@react-three/drei");
|
|
4157
|
-
var
|
|
4288
|
+
var import_three17 = require("three");
|
|
4158
4289
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4159
4290
|
var LINE_COLOR = "#22d3ee";
|
|
4160
4291
|
var BOX_COLOR = "#facc15";
|
|
@@ -4182,8 +4313,8 @@ function DimensionsBox({ box, unit }) {
|
|
|
4182
4313
|
);
|
|
4183
4314
|
const edges = (0, import_react13.useMemo)(() => {
|
|
4184
4315
|
const [w2, h2, d2] = box.size;
|
|
4185
|
-
const geometry = new
|
|
4186
|
-
new
|
|
4316
|
+
const geometry = new import_three17.EdgesGeometry(
|
|
4317
|
+
new import_three17.BoxGeometry(w2 || 1e-4, h2 || 1e-4, d2 || 1e-4)
|
|
4187
4318
|
);
|
|
4188
4319
|
return geometry;
|
|
4189
4320
|
}, [box.size]);
|
|
@@ -4229,7 +4360,7 @@ function MeasurementLayer({
|
|
|
4229
4360
|
points.slice(1).map((point, index) => {
|
|
4230
4361
|
const a = points[index].position;
|
|
4231
4362
|
const b = point.position;
|
|
4232
|
-
const distance = new
|
|
4363
|
+
const distance = new import_three17.Vector3(...a).distanceTo(new import_three17.Vector3(...b));
|
|
4233
4364
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("group", { children: [
|
|
4234
4365
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_drei5.Line, { points: [a, b], color: LINE_COLOR, lineWidth: 2 }),
|
|
4235
4366
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MeasureLabel, { position: midpoint(a, b), children: formatMeasurement(distance, unit) })
|
|
@@ -4243,7 +4374,7 @@ function MeasurementLayer({
|
|
|
4243
4374
|
var import_react14 = require("react");
|
|
4244
4375
|
var import_xr3 = require("@react-three/xr");
|
|
4245
4376
|
var import_fiber9 = require("@react-three/fiber");
|
|
4246
|
-
var
|
|
4377
|
+
var import_three18 = require("three");
|
|
4247
4378
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
4248
4379
|
var TARGET_SIZE = 1;
|
|
4249
4380
|
var FORWARD_DISTANCE = 1;
|
|
@@ -4280,13 +4411,13 @@ var XRModelPresenter = (0, import_react14.forwardRef)(
|
|
|
4280
4411
|
() => box ? computeNormalization(box, scaleMode) : null,
|
|
4281
4412
|
[box, scaleMode]
|
|
4282
4413
|
);
|
|
4283
|
-
const placedPosition = (0, import_react14.useRef)(new
|
|
4414
|
+
const placedPosition = (0, import_react14.useRef)(new import_three18.Vector3(0, 0, -FORWARD_DISTANCE));
|
|
4284
4415
|
const userScale = (0, import_react14.useRef)(1);
|
|
4285
4416
|
const rotationY = (0, import_react14.useRef)(0);
|
|
4286
4417
|
const placementMode = (0, import_react14.useRef)(true);
|
|
4287
4418
|
const modelPlaced = (0, import_react14.useRef)(false);
|
|
4288
|
-
const hitMatrix = (0, import_react14.useMemo)(() => new
|
|
4289
|
-
const hitPosition = (0, import_react14.useRef)(new
|
|
4419
|
+
const hitMatrix = (0, import_react14.useMemo)(() => new import_three18.Matrix4(), []);
|
|
4420
|
+
const hitPosition = (0, import_react14.useRef)(new import_three18.Vector3());
|
|
4290
4421
|
const hasHit = (0, import_react14.useRef)(false);
|
|
4291
4422
|
const lastARState = (0, import_react14.useRef)(null);
|
|
4292
4423
|
const gesturing = (0, import_react14.useRef)(false);
|
|
@@ -4479,7 +4610,7 @@ var XRModelPresenter_default = XRModelPresenter;
|
|
|
4479
4610
|
// src/components/ModelViewer/CinematicCamera.tsx
|
|
4480
4611
|
var import_react15 = require("react");
|
|
4481
4612
|
var import_fiber10 = require("@react-three/fiber");
|
|
4482
|
-
var
|
|
4613
|
+
var import_three19 = require("three");
|
|
4483
4614
|
var ENTER_BLEND_SECONDS = 1.2;
|
|
4484
4615
|
function CinematicCamera({
|
|
4485
4616
|
controlsRef,
|
|
@@ -4558,14 +4689,14 @@ function CinematicCamera({
|
|
|
4558
4689
|
const curves = (0, import_react15.useMemo)(() => {
|
|
4559
4690
|
if (!hasPath) return null;
|
|
4560
4691
|
return {
|
|
4561
|
-
position: new
|
|
4562
|
-
waypoints.map((w) => new
|
|
4692
|
+
position: new import_three19.CatmullRomCurve3(
|
|
4693
|
+
waypoints.map((w) => new import_three19.Vector3(...w.position)),
|
|
4563
4694
|
loop,
|
|
4564
4695
|
"catmullrom",
|
|
4565
4696
|
0.5
|
|
4566
4697
|
),
|
|
4567
|
-
target: new
|
|
4568
|
-
waypoints.map((w) => new
|
|
4698
|
+
target: new import_three19.CatmullRomCurve3(
|
|
4699
|
+
waypoints.map((w) => new import_three19.Vector3(...w.target)),
|
|
4569
4700
|
loop,
|
|
4570
4701
|
"catmullrom",
|
|
4571
4702
|
0.5
|
|
@@ -4581,8 +4712,8 @@ function CinematicCamera({
|
|
|
4581
4712
|
const points = waypoints.map((waypoint) => ({
|
|
4582
4713
|
azimuth: waypoint.azimuthAngle,
|
|
4583
4714
|
polar: waypoint.polarAngle,
|
|
4584
|
-
distance: new
|
|
4585
|
-
new
|
|
4715
|
+
distance: new import_three19.Vector3(...waypoint.position).distanceTo(
|
|
4716
|
+
new import_three19.Vector3(...waypoint.target)
|
|
4586
4717
|
)
|
|
4587
4718
|
}));
|
|
4588
4719
|
for (let index = 1; index < points.length; index += 1) {
|
|
@@ -4594,15 +4725,15 @@ function CinematicCamera({
|
|
|
4594
4725
|
}, [signature, hasPath]);
|
|
4595
4726
|
const elapsedRef = (0, import_react15.useRef)(0);
|
|
4596
4727
|
const enterElapsedRef = (0, import_react15.useRef)(0);
|
|
4597
|
-
const enterPos = (0, import_react15.useRef)(new
|
|
4598
|
-
const enterTarget = (0, import_react15.useRef)(new
|
|
4728
|
+
const enterPos = (0, import_react15.useRef)(new import_three19.Vector3());
|
|
4729
|
+
const enterTarget = (0, import_react15.useRef)(new import_three19.Vector3());
|
|
4599
4730
|
const startedRef = (0, import_react15.useRef)(false);
|
|
4600
4731
|
const pausedElapsedRef = (0, import_react15.useRef)(0);
|
|
4601
4732
|
const hasFinishedRef = (0, import_react15.useRef)(false);
|
|
4602
4733
|
const orbitRef = (0, import_react15.useRef)(null);
|
|
4603
|
-
const tmpPos = (0, import_react15.useMemo)(() => new
|
|
4604
|
-
const tmpTarget = (0, import_react15.useMemo)(() => new
|
|
4605
|
-
const tmpSpherical = (0, import_react15.useMemo)(() => new
|
|
4734
|
+
const tmpPos = (0, import_react15.useMemo)(() => new import_three19.Vector3(), []);
|
|
4735
|
+
const tmpTarget = (0, import_react15.useMemo)(() => new import_three19.Vector3(), []);
|
|
4736
|
+
const tmpSpherical = (0, import_react15.useMemo)(() => new import_three19.Spherical(), []);
|
|
4606
4737
|
(0, import_react15.useEffect)(() => {
|
|
4607
4738
|
elapsedRef.current = 0;
|
|
4608
4739
|
pausedElapsedRef.current = 0;
|
|
@@ -4653,7 +4784,7 @@ function CinematicCamera({
|
|
|
4653
4784
|
if (!hasPath) {
|
|
4654
4785
|
const scene = sceneRef.current;
|
|
4655
4786
|
if (scene) {
|
|
4656
|
-
const sphere = new
|
|
4787
|
+
const sphere = new import_three19.Box3().setFromObject(scene).getBoundingSphere(new import_three19.Sphere());
|
|
4657
4788
|
orbitRef.current = {
|
|
4658
4789
|
center: sphere.center.clone(),
|
|
4659
4790
|
radius: sphere.radius > 0 ? sphere.radius : 1
|
|
@@ -5817,7 +5948,7 @@ function consumeInitialAutoFitOverride(controls) {
|
|
|
5817
5948
|
var import_react22 = require("react");
|
|
5818
5949
|
var import_fiber11 = require("@react-three/fiber");
|
|
5819
5950
|
var import_drei6 = require("@react-three/drei");
|
|
5820
|
-
var
|
|
5951
|
+
var import_three20 = require("three");
|
|
5821
5952
|
|
|
5822
5953
|
// src/assets/light-gizmos/sun.png
|
|
5823
5954
|
var sun_default = "data:image/png;base64,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";
|
|
@@ -5840,7 +5971,7 @@ var RING_SCREEN_SIZE = SUN_SCREEN_SIZE * 3;
|
|
|
5840
5971
|
var RING_COLOR = "#4d7dff";
|
|
5841
5972
|
var LINE_COLOR2 = "#ffcc00";
|
|
5842
5973
|
var LINE_GLOW_RADIUS = 0.02;
|
|
5843
|
-
var UP_AXIS = new
|
|
5974
|
+
var UP_AXIS = new import_three20.Vector3(0, 1, 0);
|
|
5844
5975
|
var AXIS_ARROW_LENGTH = 1.4;
|
|
5845
5976
|
var AXIS_CONE_LENGTH = 0.35;
|
|
5846
5977
|
var AXIS_CONE_RADIUS = 0.13;
|
|
@@ -5852,17 +5983,17 @@ var AXIS_COLORS = {
|
|
|
5852
5983
|
z: "#4444ff"
|
|
5853
5984
|
};
|
|
5854
5985
|
function axisVector(axis) {
|
|
5855
|
-
return new
|
|
5986
|
+
return new import_three20.Vector3(axis === "x" ? 1 : 0, axis === "y" ? 1 : 0, axis === "z" ? 1 : 0);
|
|
5856
5987
|
}
|
|
5857
5988
|
function computeAxisDragPlaneNormal(axis, eye) {
|
|
5858
5989
|
const axisVec = axisVector(axis);
|
|
5859
5990
|
if (eye.lengthSq() < 1e-8) {
|
|
5860
5991
|
eye = axisVec.clone();
|
|
5861
5992
|
}
|
|
5862
|
-
let normal = new
|
|
5993
|
+
let normal = new import_three20.Vector3().crossVectors(axisVec, new import_three20.Vector3().crossVectors(eye, axisVec));
|
|
5863
5994
|
if (normal.lengthSq() < 1e-8) {
|
|
5864
|
-
const helper = Math.abs(axisVec.y) < 0.9 ? UP_AXIS : new
|
|
5865
|
-
normal = new
|
|
5995
|
+
const helper = Math.abs(axisVec.y) < 0.9 ? UP_AXIS : new import_three20.Vector3(1, 0, 0);
|
|
5996
|
+
normal = new import_three20.Vector3().crossVectors(axisVec, helper);
|
|
5866
5997
|
}
|
|
5867
5998
|
return normal.normalize();
|
|
5868
5999
|
}
|
|
@@ -5934,18 +6065,18 @@ function LightHelpers({
|
|
|
5934
6065
|
const shaftYRef = (0, import_react22.useRef)(null);
|
|
5935
6066
|
const shaftZRef = (0, import_react22.useRef)(null);
|
|
5936
6067
|
const axisDragRef = (0, import_react22.useRef)({ dragging: false, axis: null });
|
|
5937
|
-
const axisDragPlaneRef = (0, import_react22.useRef)(new
|
|
5938
|
-
const dragStartPosRef = (0, import_react22.useRef)(new
|
|
6068
|
+
const axisDragPlaneRef = (0, import_react22.useRef)(new import_three20.Plane());
|
|
6069
|
+
const dragStartPosRef = (0, import_react22.useRef)(new import_three20.Vector3());
|
|
5939
6070
|
const dragLineRef = (0, import_react22.useRef)(null);
|
|
5940
6071
|
const dragLineGeomRef = (0, import_react22.useRef)(null);
|
|
5941
|
-
const currentPosRef = (0, import_react22.useRef)(new
|
|
6072
|
+
const currentPosRef = (0, import_react22.useRef)(new import_three20.Vector3());
|
|
5942
6073
|
const isDraggingRef = (0, import_react22.useRef)(false);
|
|
5943
|
-
const dragPlaneRef = (0, import_react22.useRef)(new
|
|
6074
|
+
const dragPlaneRef = (0, import_react22.useRef)(new import_three20.Plane());
|
|
5944
6075
|
const onDraggingChangeRef = (0, import_react22.useRef)(onDraggingChange);
|
|
5945
6076
|
(0, import_react22.useEffect)(() => {
|
|
5946
6077
|
onDraggingChangeRef.current = onDraggingChange;
|
|
5947
6078
|
}, [onDraggingChange]);
|
|
5948
|
-
const lightPos = (0, import_react22.useMemo)(() => new
|
|
6079
|
+
const lightPos = (0, import_react22.useMemo)(() => new import_three20.Vector3(position[0], position[1], position[2]), [position]);
|
|
5949
6080
|
const linePositions = (0, import_react22.useMemo)(() => new Float32Array(6), []);
|
|
5950
6081
|
const dragLinePositions = (0, import_react22.useMemo)(() => new Float32Array(6), []);
|
|
5951
6082
|
const ringXPositions = (0, import_react22.useMemo)(() => makeRingPositions("x"), []);
|
|
@@ -5955,7 +6086,7 @@ function LightHelpers({
|
|
|
5955
6086
|
const iconPath = isPointLight ? BULB_ICON_PATH : SUN_ICON_PATH;
|
|
5956
6087
|
const iconScreenSize = isPointLight ? BULB_SCREEN_SIZE : SUN_SCREEN_SIZE;
|
|
5957
6088
|
const sunTexture = (0, import_react22.useMemo)(() => {
|
|
5958
|
-
const loader = new
|
|
6089
|
+
const loader = new import_three20.TextureLoader();
|
|
5959
6090
|
return loader.load(iconPath);
|
|
5960
6091
|
}, [iconPath]);
|
|
5961
6092
|
const activeGizmoId = (0, import_react22.useSyncExternalStore)(subscribeActiveGizmo, getActiveGizmoSnapshot, getActiveGizmoSnapshot);
|
|
@@ -6062,7 +6193,7 @@ function LightHelpers({
|
|
|
6062
6193
|
(0, import_react22.useEffect)(() => {
|
|
6063
6194
|
const getMouseNdc = (event) => {
|
|
6064
6195
|
const rect = gl.domElement.getBoundingClientRect();
|
|
6065
|
-
return new
|
|
6196
|
+
return new import_three20.Vector2(
|
|
6066
6197
|
(event.clientX - rect.left) / rect.width * 2 - 1,
|
|
6067
6198
|
-((event.clientY - rect.top) / rect.height) * 2 + 1
|
|
6068
6199
|
);
|
|
@@ -6104,12 +6235,12 @@ function LightHelpers({
|
|
|
6104
6235
|
const axis = axisDragRef.current.axis;
|
|
6105
6236
|
const currentPos = currentPosRef.current;
|
|
6106
6237
|
const axisVec = axisVector(axis);
|
|
6107
|
-
const eye = new
|
|
6238
|
+
const eye = new import_three20.Vector3().subVectors(camera.position, currentPos);
|
|
6108
6239
|
const planeNormal = computeAxisDragPlaneNormal(axis, eye);
|
|
6109
6240
|
axisDragPlaneRef.current.setFromNormalAndCoplanarPoint(planeNormal, currentPos);
|
|
6110
6241
|
const mouse2 = getMouseNdc(event);
|
|
6111
6242
|
raycaster.setFromCamera(mouse2, camera);
|
|
6112
|
-
const intersection2 = new
|
|
6243
|
+
const intersection2 = new import_three20.Vector3();
|
|
6113
6244
|
const hitPoint2 = raycaster.ray.intersectPlane(axisDragPlaneRef.current, intersection2);
|
|
6114
6245
|
if (!hitPoint2) return;
|
|
6115
6246
|
const toPoint = hitPoint2.clone().sub(currentPos);
|
|
@@ -6128,7 +6259,7 @@ function LightHelpers({
|
|
|
6128
6259
|
if (!isDraggingRef.current) return;
|
|
6129
6260
|
const mouse = getMouseNdc(event);
|
|
6130
6261
|
raycaster.setFromCamera(mouse, camera);
|
|
6131
|
-
const intersection = new
|
|
6262
|
+
const intersection = new import_three20.Vector3();
|
|
6132
6263
|
const hitPoint = raycaster.ray.intersectPlane(dragPlaneRef.current, intersection);
|
|
6133
6264
|
if (!hitPoint) return;
|
|
6134
6265
|
const newPos = [
|
|
@@ -6175,7 +6306,7 @@ function LightHelpers({
|
|
|
6175
6306
|
setActiveTab?.("scene");
|
|
6176
6307
|
setActiveSubTab?.("Lighting");
|
|
6177
6308
|
}
|
|
6178
|
-
const cameraDir = new
|
|
6309
|
+
const cameraDir = new import_three20.Vector3();
|
|
6179
6310
|
camera.getWorldDirection(cameraDir);
|
|
6180
6311
|
dragPlaneRef.current.setFromNormalAndCoplanarPoint(cameraDir, currentPosRef.current);
|
|
6181
6312
|
isDraggingRef.current = true;
|
|
@@ -6238,7 +6369,7 @@ function LightHelpers({
|
|
|
6238
6369
|
map: sunTexture,
|
|
6239
6370
|
transparent: true,
|
|
6240
6371
|
opacity: 0.9,
|
|
6241
|
-
blending:
|
|
6372
|
+
blending: import_three20.AdditiveBlending,
|
|
6242
6373
|
depthWrite: false
|
|
6243
6374
|
},
|
|
6244
6375
|
iconPath
|
|
@@ -6308,17 +6439,17 @@ function LightHelpers({
|
|
|
6308
6439
|
] }),
|
|
6309
6440
|
gizmoVisible && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("group", { ref: axisGroupRef, children: axisArrows.map((axis) => {
|
|
6310
6441
|
const axisColor = AXIS_COLORS[axis];
|
|
6311
|
-
const end = new
|
|
6442
|
+
const end = new import_three20.Vector3(
|
|
6312
6443
|
axis === "x" ? AXIS_ARROW_LENGTH : 0,
|
|
6313
6444
|
axis === "y" ? AXIS_ARROW_LENGTH : 0,
|
|
6314
6445
|
axis === "z" ? AXIS_ARROW_LENGTH : 0
|
|
6315
6446
|
);
|
|
6316
|
-
const conePos = new
|
|
6447
|
+
const conePos = new import_three20.Vector3(
|
|
6317
6448
|
axis === "x" ? AXIS_ARROW_LENGTH - AXIS_CONE_LENGTH / 2 : 0,
|
|
6318
6449
|
axis === "y" ? AXIS_ARROW_LENGTH - AXIS_CONE_LENGTH / 2 : 0,
|
|
6319
6450
|
axis === "z" ? AXIS_ARROW_LENGTH - AXIS_CONE_LENGTH / 2 : 0
|
|
6320
6451
|
);
|
|
6321
|
-
const shaftPos = new
|
|
6452
|
+
const shaftPos = new import_three20.Vector3(
|
|
6322
6453
|
axis === "x" ? AXIS_ARROW_LENGTH / 2 : 0,
|
|
6323
6454
|
axis === "y" ? AXIS_ARROW_LENGTH / 2 : 0,
|
|
6324
6455
|
axis === "z" ? AXIS_ARROW_LENGTH / 2 : 0
|
|
@@ -6330,7 +6461,7 @@ function LightHelpers({
|
|
|
6330
6461
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6331
6462
|
import_drei6.Line,
|
|
6332
6463
|
{
|
|
6333
|
-
points: [new
|
|
6464
|
+
points: [new import_three20.Vector3(0, 0, 0), end],
|
|
6334
6465
|
color: axisColor,
|
|
6335
6466
|
transparent: true,
|
|
6336
6467
|
opacity: 0.9,
|
|
@@ -6358,7 +6489,7 @@ function LightHelpers({
|
|
|
6358
6489
|
color: LINE_COLOR2,
|
|
6359
6490
|
transparent: true,
|
|
6360
6491
|
opacity: 0.05,
|
|
6361
|
-
blending:
|
|
6492
|
+
blending: import_three20.AdditiveBlending,
|
|
6362
6493
|
depthWrite: false,
|
|
6363
6494
|
depthTest: false
|
|
6364
6495
|
}
|
|
@@ -6379,7 +6510,7 @@ function LightHelpers({
|
|
|
6379
6510
|
color: LINE_COLOR2,
|
|
6380
6511
|
transparent: true,
|
|
6381
6512
|
opacity: 0.7,
|
|
6382
|
-
blending:
|
|
6513
|
+
blending: import_three20.AdditiveBlending
|
|
6383
6514
|
}
|
|
6384
6515
|
)
|
|
6385
6516
|
] })
|
|
@@ -6419,7 +6550,7 @@ function findInfluencingBone(hit) {
|
|
|
6419
6550
|
if (!skinIndex || !skinWeight || !position) return null;
|
|
6420
6551
|
const localHit = mesh.worldToLocal(hit.point.clone());
|
|
6421
6552
|
const vertices = [hit.face.a, hit.face.b, hit.face.c];
|
|
6422
|
-
const vertex = new
|
|
6553
|
+
const vertex = new import_three21.Vector3();
|
|
6423
6554
|
let nearest = vertices[0];
|
|
6424
6555
|
let nearestDist = Infinity;
|
|
6425
6556
|
for (const vi of vertices) {
|
|
@@ -6469,9 +6600,9 @@ function GuidedTourCameraFollow({
|
|
|
6469
6600
|
const scene = (0, import_fiber12.useThree)((state) => state.scene);
|
|
6470
6601
|
const nodeRef = (0, import_react23.useRef)(null);
|
|
6471
6602
|
const hasPrev = (0, import_react23.useRef)(false);
|
|
6472
|
-
const live = (0, import_react23.useMemo)(() => new
|
|
6473
|
-
const prev = (0, import_react23.useMemo)(() => new
|
|
6474
|
-
const goal = (0, import_react23.useMemo)(() => new
|
|
6603
|
+
const live = (0, import_react23.useMemo)(() => new import_three21.Vector3(), []);
|
|
6604
|
+
const prev = (0, import_react23.useMemo)(() => new import_three21.Vector3(), []);
|
|
6605
|
+
const goal = (0, import_react23.useMemo)(() => new import_three21.Vector3(), []);
|
|
6475
6606
|
const nodeName = annotation?.anchorNodeName;
|
|
6476
6607
|
const localPosition = annotation?.anchorLocalPosition;
|
|
6477
6608
|
(0, import_react23.useEffect)(() => {
|
|
@@ -6510,8 +6641,8 @@ var DEFAULT_AR_OVERLAY_STATE = {
|
|
|
6510
6641
|
isModelPlaced: false
|
|
6511
6642
|
};
|
|
6512
6643
|
function computeMeasureBox(scene) {
|
|
6513
|
-
const box = new
|
|
6514
|
-
const size = new
|
|
6644
|
+
const box = new import_three21.Box3().setFromObject(scene);
|
|
6645
|
+
const size = new import_three21.Vector3();
|
|
6515
6646
|
box.getSize(size);
|
|
6516
6647
|
return {
|
|
6517
6648
|
min: [box.min.x, box.min.y, box.min.z],
|
|
@@ -6530,18 +6661,18 @@ function computeUvMeshStats(scene) {
|
|
|
6530
6661
|
return stats;
|
|
6531
6662
|
}
|
|
6532
6663
|
function computeModelBounds(scene) {
|
|
6533
|
-
const box = new
|
|
6664
|
+
const box = new import_three21.Box3().setFromObject(scene);
|
|
6534
6665
|
if (box.isEmpty()) return null;
|
|
6535
|
-
const center = box.getCenter(new
|
|
6536
|
-
const radius = box.getSize(new
|
|
6666
|
+
const center = box.getCenter(new import_three21.Vector3());
|
|
6667
|
+
const radius = box.getSize(new import_three21.Vector3()).length() / 2;
|
|
6537
6668
|
if (!Number.isFinite(radius) || radius <= 0) return null;
|
|
6538
6669
|
return { center: [center.x, center.y, center.z], radius };
|
|
6539
6670
|
}
|
|
6540
6671
|
function fitClippingPlanesToScene(scene, controls) {
|
|
6541
6672
|
const camera = controls?.camera;
|
|
6542
|
-
if (!(camera instanceof
|
|
6543
|
-
const box = new
|
|
6544
|
-
const size = box.getSize(new
|
|
6673
|
+
if (!(camera instanceof import_three21.PerspectiveCamera)) return;
|
|
6674
|
+
const box = new import_three21.Box3().setFromObject(scene);
|
|
6675
|
+
const size = box.getSize(new import_three21.Vector3()).length();
|
|
6545
6676
|
if (!Number.isFinite(size) || size <= 0) return;
|
|
6546
6677
|
camera.near = size / 100;
|
|
6547
6678
|
camera.far = size * 100;
|
|
@@ -6726,8 +6857,8 @@ function ModelViewer({
|
|
|
6726
6857
|
if (!controls || initialCameraStateRef.current) {
|
|
6727
6858
|
return;
|
|
6728
6859
|
}
|
|
6729
|
-
const position = controls.getPosition(new
|
|
6730
|
-
const target = controls.getTarget(new
|
|
6860
|
+
const position = controls.getPosition(new import_three21.Vector3());
|
|
6861
|
+
const target = controls.getTarget(new import_three21.Vector3());
|
|
6731
6862
|
initialCameraStateRef.current = {
|
|
6732
6863
|
position: [position.x, position.y, position.z],
|
|
6733
6864
|
target: [target.x, target.y, target.z]
|
|
@@ -6985,7 +7116,7 @@ function ModelViewer({
|
|
|
6985
7116
|
const controls = controlsRef.current;
|
|
6986
7117
|
const scene = sceneRef.current;
|
|
6987
7118
|
if (!controls) return;
|
|
6988
|
-
const target = new
|
|
7119
|
+
const target = new import_three21.Vector3();
|
|
6989
7120
|
const livePosition = annotationWorldPositionsRef.current.get(
|
|
6990
7121
|
annotation.id
|
|
6991
7122
|
);
|
|
@@ -7003,15 +7134,15 @@ function ModelViewer({
|
|
|
7003
7134
|
controls.smoothTime = 0.6;
|
|
7004
7135
|
const storedNormal = annotation.worldNormal;
|
|
7005
7136
|
if (scene) {
|
|
7006
|
-
const box = new
|
|
7007
|
-
const modelCenter = new
|
|
7137
|
+
const box = new import_three21.Box3().setFromObject(scene);
|
|
7138
|
+
const modelCenter = new import_three21.Vector3();
|
|
7008
7139
|
box.getCenter(modelCenter);
|
|
7009
|
-
const modelSize = new
|
|
7140
|
+
const modelSize = new import_three21.Vector3();
|
|
7010
7141
|
box.getSize(modelSize);
|
|
7011
7142
|
const modelRadius = modelSize.length() * 0.2;
|
|
7012
7143
|
let outwardDir;
|
|
7013
7144
|
if (storedNormal) {
|
|
7014
|
-
outwardDir = new
|
|
7145
|
+
outwardDir = new import_three21.Vector3(
|
|
7015
7146
|
storedNormal[0],
|
|
7016
7147
|
storedNormal[1],
|
|
7017
7148
|
storedNormal[2]
|
|
@@ -7162,6 +7293,16 @@ function ModelViewer({
|
|
|
7162
7293
|
const isControlledBindings = onObjectBindingsChange !== void 0;
|
|
7163
7294
|
const currentObjectBindings = isControlledBindings ? objectBindings : internalObjectBindings;
|
|
7164
7295
|
currentObjectBindingsRef.current = currentObjectBindings;
|
|
7296
|
+
const currentBindingTransformSignature = (0, import_react23.useMemo)(
|
|
7297
|
+
() => Object.entries(currentObjectBindings).map(
|
|
7298
|
+
([bindingKey, binding]) => JSON.stringify([
|
|
7299
|
+
bindingKey,
|
|
7300
|
+
binding.modelObjectId,
|
|
7301
|
+
binding.transform ?? null
|
|
7302
|
+
])
|
|
7303
|
+
).sort().join(""),
|
|
7304
|
+
[currentObjectBindings]
|
|
7305
|
+
);
|
|
7165
7306
|
const currentHiddenObjects = (0, import_react23.useMemo)(
|
|
7166
7307
|
() => Object.fromEntries(
|
|
7167
7308
|
Object.entries(currentObjectBindings).filter(([, binding]) => binding.visible === false).map(([bindingKey]) => [bindingKey, true])
|
|
@@ -7301,7 +7442,7 @@ function ModelViewer({
|
|
|
7301
7442
|
const fallbackY = Math.max(minOffset, (rect.height - height) / 2);
|
|
7302
7443
|
const objectKey = resolveObjectKey(objectId, binding);
|
|
7303
7444
|
const object = objectKey ? nodeRefsMap.current[objectKey] : null;
|
|
7304
|
-
const
|
|
7445
|
+
const clamp3 = (value, max) => {
|
|
7305
7446
|
if (max <= minOffset) {
|
|
7306
7447
|
return minOffset;
|
|
7307
7448
|
}
|
|
@@ -7309,23 +7450,23 @@ function ModelViewer({
|
|
|
7309
7450
|
};
|
|
7310
7451
|
if (canvasContainer && cameraControls && object) {
|
|
7311
7452
|
const canvasRect = canvasContainer.getBoundingClientRect();
|
|
7312
|
-
const objectCenter = new
|
|
7313
|
-
new
|
|
7453
|
+
const objectCenter = new import_three21.Vector3();
|
|
7454
|
+
new import_three21.Box3().setFromObject(object).getCenter(objectCenter);
|
|
7314
7455
|
objectCenter.project(cameraControls);
|
|
7315
7456
|
const projectedX = (objectCenter.x + 1) / 2 * canvasRect.width + (canvasRect.left - rect.left);
|
|
7316
7457
|
const projectedY = (1 - objectCenter.y) / 2 * canvasRect.height + (canvasRect.top - rect.top);
|
|
7317
7458
|
return {
|
|
7318
7459
|
objectId,
|
|
7319
|
-
x:
|
|
7320
|
-
y:
|
|
7460
|
+
x: clamp3(projectedX + 24, maxX),
|
|
7461
|
+
y: clamp3(projectedY - height / 2, maxY)
|
|
7321
7462
|
};
|
|
7322
7463
|
}
|
|
7323
7464
|
const rawX = typeof fallbackCoords?.screenX === "number" ? fallbackCoords.screenX - rect.left : fallbackX;
|
|
7324
7465
|
const rawY = typeof fallbackCoords?.screenY === "number" ? fallbackCoords.screenY - rect.top : fallbackY;
|
|
7325
7466
|
return {
|
|
7326
7467
|
objectId,
|
|
7327
|
-
x:
|
|
7328
|
-
y:
|
|
7468
|
+
x: clamp3(rawX, maxX),
|
|
7469
|
+
y: clamp3(rawY, maxY)
|
|
7329
7470
|
};
|
|
7330
7471
|
},
|
|
7331
7472
|
[resolveObjectKey]
|
|
@@ -7334,7 +7475,6 @@ function ModelViewer({
|
|
|
7334
7475
|
(event) => {
|
|
7335
7476
|
const { objectId, action, binding } = event;
|
|
7336
7477
|
setCurrentAction(event);
|
|
7337
|
-
onAction?.(event);
|
|
7338
7478
|
switch (action.id) {
|
|
7339
7479
|
case "toggle-visibility": {
|
|
7340
7480
|
let targetKey = objectId;
|
|
@@ -7382,6 +7522,7 @@ function ModelViewer({
|
|
|
7382
7522
|
default:
|
|
7383
7523
|
break;
|
|
7384
7524
|
}
|
|
7525
|
+
onAction?.(event);
|
|
7385
7526
|
},
|
|
7386
7527
|
[
|
|
7387
7528
|
applyObjectBindings,
|
|
@@ -7522,7 +7663,8 @@ function ModelViewer({
|
|
|
7522
7663
|
objectBindings: currentObjectBindingsRef.current,
|
|
7523
7664
|
nodeRefs: nodeRefsMap.current,
|
|
7524
7665
|
homeCameraState: initialCameraStateRef.current,
|
|
7525
|
-
captureImage: (options) => captureImage(rendererCaptureRef.current, options)
|
|
7666
|
+
captureImage: (options) => captureImage(rendererCaptureRef.current, options),
|
|
7667
|
+
invalidate: () => rendererCaptureRef.current?.invalidate()
|
|
7526
7668
|
});
|
|
7527
7669
|
}, []);
|
|
7528
7670
|
const fitScene = (0, import_react23.useCallback)(
|
|
@@ -7534,14 +7676,14 @@ function ModelViewer({
|
|
|
7534
7676
|
}
|
|
7535
7677
|
try {
|
|
7536
7678
|
if (flyIn) {
|
|
7537
|
-
const target = controls.getTarget(new
|
|
7538
|
-
const position = controls.getPosition(new
|
|
7679
|
+
const target = controls.getTarget(new import_three21.Vector3());
|
|
7680
|
+
const position = controls.getPosition(new import_three21.Vector3());
|
|
7539
7681
|
const direction = position.clone().sub(target);
|
|
7540
7682
|
if (direction.lengthSq() < 1e-6) {
|
|
7541
7683
|
direction.set(0, 0, 1);
|
|
7542
7684
|
}
|
|
7543
7685
|
direction.normalize();
|
|
7544
|
-
const sphere = new
|
|
7686
|
+
const sphere = new import_three21.Box3().setFromObject(scene).getBoundingSphere(new import_three21.Sphere());
|
|
7545
7687
|
const farDistance = Math.max(sphere.radius * 10, 20);
|
|
7546
7688
|
const farPosition = target.clone().add(direction.multiplyScalar(farDistance));
|
|
7547
7689
|
await controls.setLookAt(
|
|
@@ -7853,6 +7995,13 @@ function ModelViewer({
|
|
|
7853
7995
|
);
|
|
7854
7996
|
setBindingsMismatch(!hasAnyMatch);
|
|
7855
7997
|
}, [modelLoaded, currentObjectBindings]);
|
|
7998
|
+
(0, import_react23.useEffect)(() => {
|
|
7999
|
+
const scene = sceneRef.current;
|
|
8000
|
+
if (!modelLoaded || !scene) return;
|
|
8001
|
+
scene.updateMatrixWorld(true);
|
|
8002
|
+
setMeasureBox(computeMeasureBox(scene));
|
|
8003
|
+
setModelBounds(computeModelBounds(scene));
|
|
8004
|
+
}, [modelLoaded, currentBindingTransformSignature]);
|
|
7856
8005
|
const clearMeasurements = (0, import_react23.useCallback)(() => setMeasurePoints([]), []);
|
|
7857
8006
|
const handleMeasurePointerDown = (0, import_react23.useCallback)(
|
|
7858
8007
|
(event) => {
|
|
@@ -7878,8 +8027,8 @@ function ModelViewer({
|
|
|
7878
8027
|
const rect = canvas.getBoundingClientRect();
|
|
7879
8028
|
const ndcX = (event.clientX - rect.left) / rect.width * 2 - 1;
|
|
7880
8029
|
const ndcY = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
|
7881
|
-
const raycaster = new
|
|
7882
|
-
raycaster.setFromCamera(new
|
|
8030
|
+
const raycaster = new import_three21.Raycaster();
|
|
8031
|
+
raycaster.setFromCamera(new import_three21.Vector2(ndcX, ndcY), cam);
|
|
7883
8032
|
const hits = raycaster.intersectObject(scene, true);
|
|
7884
8033
|
if (hits.length === 0) return;
|
|
7885
8034
|
const { point } = hits[0];
|
|
@@ -7896,7 +8045,11 @@ function ModelViewer({
|
|
|
7896
8045
|
);
|
|
7897
8046
|
(0, import_react23.useEffect)(() => {
|
|
7898
8047
|
setMeasurePoints([]);
|
|
7899
|
-
}, [
|
|
8048
|
+
}, [
|
|
8049
|
+
modelUrl,
|
|
8050
|
+
resolvedSceneConfig.model.rotation,
|
|
8051
|
+
currentBindingTransformSignature
|
|
8052
|
+
]);
|
|
7900
8053
|
const handleDownloadMesh = (0, import_react23.useCallback)(() => {
|
|
7901
8054
|
const matRefs = materialRefsOut.current;
|
|
7902
8055
|
const scene = sceneRef.current;
|
|
@@ -8000,8 +8153,8 @@ function ModelViewer({
|
|
|
8000
8153
|
const rect = canvas.getBoundingClientRect();
|
|
8001
8154
|
const ndcX = (e.clientX - rect.left) / rect.width * 2 - 1;
|
|
8002
8155
|
const ndcY = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
|
8003
|
-
const raycaster = new
|
|
8004
|
-
raycaster.setFromCamera(new
|
|
8156
|
+
const raycaster = new import_three21.Raycaster();
|
|
8157
|
+
raycaster.setFromCamera(new import_three21.Vector2(ndcX, ndcY), cam);
|
|
8005
8158
|
const hits = raycaster.intersectObject(scene, true);
|
|
8006
8159
|
if (hits.length === 0) return;
|
|
8007
8160
|
const hit = hits[0];
|
|
@@ -8239,11 +8392,13 @@ function ModelViewer({
|
|
|
8239
8392
|
shadowsEnabled: shadows,
|
|
8240
8393
|
environmentRotation: resolvedSceneConfig.environment.rotation,
|
|
8241
8394
|
environmentConfig: resolvedSceneConfig.environment,
|
|
8242
|
-
modelBounds
|
|
8395
|
+
modelBounds,
|
|
8396
|
+
objectBindings: currentObjectBindings,
|
|
8397
|
+
nodeRefs: nodeRefsMap
|
|
8243
8398
|
}
|
|
8244
8399
|
),
|
|
8245
8400
|
showLightHelpers && resolvedSceneConfig.lighting.lights.map((light) => {
|
|
8246
|
-
if (!light.visible || light.type === "none" || light.type === "hemisphere") {
|
|
8401
|
+
if (!light.visible || light.type === "none" || light.type === "hemisphere" || light.attachment) {
|
|
8247
8402
|
return null;
|
|
8248
8403
|
}
|
|
8249
8404
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
@@ -8885,7 +9040,7 @@ function ModelViewer({
|
|
|
8885
9040
|
}
|
|
8886
9041
|
|
|
8887
9042
|
// src/components/BindingBuilder/BindingBuilder.tsx
|
|
8888
|
-
var
|
|
9043
|
+
var import_react42 = require("react");
|
|
8889
9044
|
var import_lucide_react16 = require("lucide-react");
|
|
8890
9045
|
|
|
8891
9046
|
// src/styles/BindingBuilder.css
|
|
@@ -8893,32 +9048,13 @@ styleInject('.bb-root {\n --bb-font-family:\n Inter,\n "Segoe UI",\n H
|
|
|
8893
9048
|
|
|
8894
9049
|
// src/hooks/useViewerCamera.ts
|
|
8895
9050
|
var import_react24 = require("react");
|
|
8896
|
-
var
|
|
8897
|
-
|
|
8898
|
-
// src/utils/resolveBindingKey.ts
|
|
8899
|
-
function resolveBindingKey(objectBindings, objectId) {
|
|
8900
|
-
if (objectBindings[objectId]) {
|
|
8901
|
-
return objectId;
|
|
8902
|
-
}
|
|
8903
|
-
const idMatch = Object.entries(objectBindings).find(
|
|
8904
|
-
([, binding]) => binding.id === objectId
|
|
8905
|
-
)?.[0];
|
|
8906
|
-
if (idMatch) {
|
|
8907
|
-
return idMatch;
|
|
8908
|
-
}
|
|
8909
|
-
const modelObjectMatch = Object.entries(objectBindings).find(
|
|
8910
|
-
([, binding]) => binding.modelObjectId === objectId
|
|
8911
|
-
)?.[0];
|
|
8912
|
-
return modelObjectMatch ?? null;
|
|
8913
|
-
}
|
|
8914
|
-
|
|
8915
|
-
// src/hooks/useViewerCamera.ts
|
|
9051
|
+
var import_three22 = require("three");
|
|
8916
9052
|
function toTuple(vector) {
|
|
8917
9053
|
return [vector.x, vector.y, vector.z];
|
|
8918
9054
|
}
|
|
8919
9055
|
function buildCameraState(camera, controls) {
|
|
8920
|
-
const position = new
|
|
8921
|
-
const target = new
|
|
9056
|
+
const position = new import_three22.Vector3();
|
|
9057
|
+
const target = new import_three22.Vector3();
|
|
8922
9058
|
controls.getPosition(position);
|
|
8923
9059
|
controls.getTarget(target);
|
|
8924
9060
|
return {
|
|
@@ -8945,11 +9081,16 @@ async function runSmoothCameraTransition2(controls, action, smoothTime = 0.6) {
|
|
|
8945
9081
|
controls.smoothTime = originalSmoothTime;
|
|
8946
9082
|
}
|
|
8947
9083
|
}
|
|
8948
|
-
function useViewerCamera() {
|
|
9084
|
+
function useViewerCamera(options = {}) {
|
|
9085
|
+
const optionsRef = (0, import_react24.useRef)(options);
|
|
9086
|
+
optionsRef.current = options;
|
|
8949
9087
|
const viewerRef = (0, import_react24.useRef)(null);
|
|
8950
9088
|
const [cameraState, setCameraStateValue] = (0, import_react24.useState)(
|
|
8951
9089
|
null
|
|
8952
9090
|
);
|
|
9091
|
+
const [cameraPresets, setCameraPresets] = (0, import_react24.useState)(() => ({ ...options.presets }));
|
|
9092
|
+
const cameraPresetsRef = (0, import_react24.useRef)(cameraPresets);
|
|
9093
|
+
cameraPresetsRef.current = cameraPresets;
|
|
8953
9094
|
const updateCameraState = (0, import_react24.useCallback)((nextState) => {
|
|
8954
9095
|
setCameraStateValue(
|
|
8955
9096
|
(previousState) => isSameCameraState(previousState, nextState) ? previousState : nextState
|
|
@@ -8963,16 +9104,56 @@ function useViewerCamera() {
|
|
|
8963
9104
|
);
|
|
8964
9105
|
const homeCameraStateRef = (0, import_react24.useRef)(null);
|
|
8965
9106
|
const homeSceneRef = (0, import_react24.useRef)(null);
|
|
9107
|
+
const initializedControlsRef = (0, import_react24.useRef)(null);
|
|
8966
9108
|
const handleViewerReady = (0, import_react24.useCallback)((viewer) => {
|
|
8967
9109
|
viewerRef.current = viewer;
|
|
8968
|
-
|
|
9110
|
+
const currentState = buildCameraState(
|
|
9111
|
+
viewer.controls.camera,
|
|
9112
|
+
viewer.controls
|
|
9113
|
+
);
|
|
9114
|
+
updateCameraState(currentState);
|
|
8969
9115
|
if (viewer.scene !== homeSceneRef.current) {
|
|
8970
9116
|
homeSceneRef.current = viewer.scene;
|
|
8971
9117
|
homeCameraStateRef.current = null;
|
|
9118
|
+
initializedControlsRef.current = null;
|
|
8972
9119
|
}
|
|
8973
9120
|
if (viewer.homeCameraState && !homeCameraStateRef.current) {
|
|
8974
9121
|
homeCameraStateRef.current = viewer.homeCameraState;
|
|
8975
9122
|
}
|
|
9123
|
+
const { initialPosition, initialTarget, initialTransition = false } = optionsRef.current;
|
|
9124
|
+
if ((initialPosition || initialTarget) && viewer.scene && // A target-only setup should preserve ModelViewer's fitted or authored
|
|
9125
|
+
// camera position. Wait until that initial framing has settled instead
|
|
9126
|
+
// of cancelling auto-fit while the camera is still at its fallback.
|
|
9127
|
+
(initialPosition || viewer.homeCameraState) && initializedControlsRef.current !== viewer.controls) {
|
|
9128
|
+
initializedControlsRef.current = viewer.controls;
|
|
9129
|
+
if (!viewer.homeCameraState) {
|
|
9130
|
+
markInitialAutoFitOverride(viewer.controls);
|
|
9131
|
+
}
|
|
9132
|
+
const position = initialPosition ?? currentState.position;
|
|
9133
|
+
const target = initialTarget ?? currentState.target;
|
|
9134
|
+
void viewer.controls.setLookAt(
|
|
9135
|
+
position[0],
|
|
9136
|
+
position[1],
|
|
9137
|
+
position[2],
|
|
9138
|
+
target[0],
|
|
9139
|
+
target[1],
|
|
9140
|
+
target[2],
|
|
9141
|
+
initialTransition
|
|
9142
|
+
).then(() => {
|
|
9143
|
+
if (viewerRef.current?.controls !== viewer.controls) {
|
|
9144
|
+
return;
|
|
9145
|
+
}
|
|
9146
|
+
const nextState = buildCameraState(
|
|
9147
|
+
viewer.controls.camera,
|
|
9148
|
+
viewer.controls
|
|
9149
|
+
);
|
|
9150
|
+
homeCameraStateRef.current = {
|
|
9151
|
+
position: nextState.position,
|
|
9152
|
+
target: nextState.target
|
|
9153
|
+
};
|
|
9154
|
+
updateCameraState(nextState);
|
|
9155
|
+
}).catch(() => void 0);
|
|
9156
|
+
}
|
|
8976
9157
|
}, [updateCameraState]);
|
|
8977
9158
|
const resetView = (0, import_react24.useCallback)(async () => {
|
|
8978
9159
|
const viewer = viewerRef.current;
|
|
@@ -9068,27 +9249,33 @@ function useViewerCamera() {
|
|
|
9068
9249
|
return false;
|
|
9069
9250
|
}
|
|
9070
9251
|
try {
|
|
9252
|
+
if (!viewerRef.current?.homeCameraState) {
|
|
9253
|
+
markInitialAutoFitOverride(controls);
|
|
9254
|
+
}
|
|
9071
9255
|
await controls.setTarget(
|
|
9072
9256
|
target[0],
|
|
9073
9257
|
target[1],
|
|
9074
9258
|
target[2],
|
|
9075
9259
|
enableTransition
|
|
9076
9260
|
);
|
|
9261
|
+
updateCameraState(buildCameraState(controls.camera, controls));
|
|
9077
9262
|
return true;
|
|
9078
9263
|
} catch {
|
|
9079
9264
|
return false;
|
|
9080
9265
|
}
|
|
9081
9266
|
},
|
|
9082
|
-
[]
|
|
9267
|
+
[updateCameraState]
|
|
9083
9268
|
);
|
|
9084
|
-
const
|
|
9269
|
+
const applyCameraPreset = (0, import_react24.useCallback)(
|
|
9085
9270
|
async (state, enableTransition = true) => {
|
|
9086
9271
|
const controls = viewerRef.current?.controls;
|
|
9087
9272
|
if (!controls) {
|
|
9088
9273
|
return false;
|
|
9089
9274
|
}
|
|
9090
9275
|
try {
|
|
9091
|
-
|
|
9276
|
+
if (!viewerRef.current?.homeCameraState) {
|
|
9277
|
+
markInitialAutoFitOverride(controls);
|
|
9278
|
+
}
|
|
9092
9279
|
const transitions = [
|
|
9093
9280
|
controls.setLookAt(
|
|
9094
9281
|
state.position[0],
|
|
@@ -9112,11 +9299,11 @@ function useViewerCamera() {
|
|
|
9112
9299
|
await Promise.all(transitions);
|
|
9113
9300
|
const camera = controls.camera;
|
|
9114
9301
|
let projectionChanged = false;
|
|
9115
|
-
if (state.fov
|
|
9302
|
+
if (state.fov != null && "fov" in camera && typeof camera.fov === "number") {
|
|
9116
9303
|
camera.fov = state.fov;
|
|
9117
9304
|
projectionChanged = true;
|
|
9118
9305
|
}
|
|
9119
|
-
if ("zoom" in camera && typeof camera.zoom === "number") {
|
|
9306
|
+
if (state.zoom != null && "zoom" in camera && typeof camera.zoom === "number") {
|
|
9120
9307
|
camera.zoom = state.zoom;
|
|
9121
9308
|
projectionChanged = true;
|
|
9122
9309
|
}
|
|
@@ -9131,13 +9318,94 @@ function useViewerCamera() {
|
|
|
9131
9318
|
},
|
|
9132
9319
|
[updateCameraState]
|
|
9133
9320
|
);
|
|
9321
|
+
const setCameraState = (0, import_react24.useCallback)(
|
|
9322
|
+
(state, enableTransition = true) => applyCameraPreset(state, enableTransition),
|
|
9323
|
+
[applyCameraPreset]
|
|
9324
|
+
);
|
|
9325
|
+
const lookAt = (0, import_react24.useCallback)(
|
|
9326
|
+
(position, target, enableTransition = true) => applyCameraPreset({ position, target }, enableTransition),
|
|
9327
|
+
[applyCameraPreset]
|
|
9328
|
+
);
|
|
9329
|
+
const orbitTo = (0, import_react24.useCallback)(
|
|
9330
|
+
async (azimuthAngle, polarAngle, enableTransition = true) => {
|
|
9331
|
+
const controls = viewerRef.current?.controls;
|
|
9332
|
+
if (!controls) {
|
|
9333
|
+
return false;
|
|
9334
|
+
}
|
|
9335
|
+
try {
|
|
9336
|
+
if (!viewerRef.current?.homeCameraState) {
|
|
9337
|
+
markInitialAutoFitOverride(controls);
|
|
9338
|
+
}
|
|
9339
|
+
await controls.rotateTo(
|
|
9340
|
+
azimuthAngle,
|
|
9341
|
+
polarAngle,
|
|
9342
|
+
enableTransition
|
|
9343
|
+
);
|
|
9344
|
+
updateCameraState(buildCameraState(controls.camera, controls));
|
|
9345
|
+
return true;
|
|
9346
|
+
} catch {
|
|
9347
|
+
return false;
|
|
9348
|
+
}
|
|
9349
|
+
},
|
|
9350
|
+
[updateCameraState]
|
|
9351
|
+
);
|
|
9352
|
+
const dollyTo = (0, import_react24.useCallback)(
|
|
9353
|
+
async (distance, enableTransition = true) => {
|
|
9354
|
+
const controls = viewerRef.current?.controls;
|
|
9355
|
+
if (!controls) {
|
|
9356
|
+
return false;
|
|
9357
|
+
}
|
|
9358
|
+
try {
|
|
9359
|
+
if (!viewerRef.current?.homeCameraState) {
|
|
9360
|
+
markInitialAutoFitOverride(controls);
|
|
9361
|
+
}
|
|
9362
|
+
await controls.dollyTo(distance, enableTransition);
|
|
9363
|
+
updateCameraState(buildCameraState(controls.camera, controls));
|
|
9364
|
+
return true;
|
|
9365
|
+
} catch {
|
|
9366
|
+
return false;
|
|
9367
|
+
}
|
|
9368
|
+
},
|
|
9369
|
+
[updateCameraState]
|
|
9370
|
+
);
|
|
9371
|
+
const savePreset = (0, import_react24.useCallback)((name) => {
|
|
9372
|
+
const controls = viewerRef.current?.controls;
|
|
9373
|
+
const trimmedName = name.trim();
|
|
9374
|
+
if (!controls || !trimmedName) {
|
|
9375
|
+
return null;
|
|
9376
|
+
}
|
|
9377
|
+
const nextState = buildCameraState(controls.camera, controls);
|
|
9378
|
+
cameraPresetsRef.current = {
|
|
9379
|
+
...cameraPresetsRef.current,
|
|
9380
|
+
[trimmedName]: nextState
|
|
9381
|
+
};
|
|
9382
|
+
setCameraPresets((current) => ({
|
|
9383
|
+
...current,
|
|
9384
|
+
[trimmedName]: nextState
|
|
9385
|
+
}));
|
|
9386
|
+
updateCameraState(nextState);
|
|
9387
|
+
return nextState;
|
|
9388
|
+
}, [updateCameraState]);
|
|
9389
|
+
const goToPreset = (0, import_react24.useCallback)(
|
|
9390
|
+
(name, enableTransition = true) => {
|
|
9391
|
+
const preset = cameraPresetsRef.current[name];
|
|
9392
|
+
return preset ? applyCameraPreset(preset, enableTransition) : Promise.resolve(false);
|
|
9393
|
+
},
|
|
9394
|
+
[applyCameraPreset]
|
|
9395
|
+
);
|
|
9134
9396
|
return {
|
|
9135
9397
|
cameraState,
|
|
9398
|
+
cameraPresets,
|
|
9136
9399
|
resetView,
|
|
9137
9400
|
focusObject,
|
|
9138
9401
|
fitScene,
|
|
9139
9402
|
setCameraTarget,
|
|
9140
9403
|
setCameraState,
|
|
9404
|
+
lookAt,
|
|
9405
|
+
orbitTo,
|
|
9406
|
+
dollyTo,
|
|
9407
|
+
savePreset,
|
|
9408
|
+
goToPreset,
|
|
9141
9409
|
handleCameraChange,
|
|
9142
9410
|
handleViewerReady
|
|
9143
9411
|
};
|
|
@@ -14994,6 +15262,9 @@ function IdentityPanel({
|
|
|
14994
15262
|
] }) });
|
|
14995
15263
|
}
|
|
14996
15264
|
|
|
15265
|
+
// src/components/BindingBuilder/components/BasicsPanel.tsx
|
|
15266
|
+
var import_react38 = require("react");
|
|
15267
|
+
|
|
14997
15268
|
// src/components/BindingBuilder/utils/constants.ts
|
|
14998
15269
|
var typeSuggestions = [
|
|
14999
15270
|
"other",
|
|
@@ -15033,6 +15304,31 @@ function BasicsPanel({
|
|
|
15033
15304
|
onToggle,
|
|
15034
15305
|
updateBinding
|
|
15035
15306
|
}) {
|
|
15307
|
+
const [groupDraft, setGroupDraft] = (0, import_react38.useState)(selectedBinding.group ?? "");
|
|
15308
|
+
const [tagsDraft, setTagsDraft] = (0, import_react38.useState)(
|
|
15309
|
+
selectedBinding.tags?.join(", ") ?? ""
|
|
15310
|
+
);
|
|
15311
|
+
(0, import_react38.useEffect)(() => {
|
|
15312
|
+
setGroupDraft(selectedBinding.group ?? "");
|
|
15313
|
+
setTagsDraft(selectedBinding.tags?.join(", ") ?? "");
|
|
15314
|
+
}, [selectedItem, selectedBinding.group, selectedBinding.tags]);
|
|
15315
|
+
const commitGroup = () => {
|
|
15316
|
+
updateBinding(selectedItem, (binding) => ({
|
|
15317
|
+
...binding,
|
|
15318
|
+
group: groupDraft.trim() || void 0
|
|
15319
|
+
}));
|
|
15320
|
+
};
|
|
15321
|
+
const commitTags = () => {
|
|
15322
|
+
const tags = [
|
|
15323
|
+
...new Set(
|
|
15324
|
+
tagsDraft.split(",").map((tag) => tag.trim()).filter(Boolean)
|
|
15325
|
+
)
|
|
15326
|
+
];
|
|
15327
|
+
updateBinding(selectedItem, (binding) => ({
|
|
15328
|
+
...binding,
|
|
15329
|
+
tags: tags.length > 0 ? tags : void 0
|
|
15330
|
+
}));
|
|
15331
|
+
};
|
|
15036
15332
|
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(BBSection, { title: "Basics", open, onToggle, children: [
|
|
15037
15333
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "bb-grid", children: [
|
|
15038
15334
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "bb-field", children: [
|
|
@@ -15079,6 +15375,38 @@ function BasicsPanel({
|
|
|
15079
15375
|
children: statusOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: option, children: option }, option))
|
|
15080
15376
|
}
|
|
15081
15377
|
)
|
|
15378
|
+
] }),
|
|
15379
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "bb-field", children: [
|
|
15380
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("label", { className: "bb-label", children: "Group" }),
|
|
15381
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
15382
|
+
"input",
|
|
15383
|
+
{
|
|
15384
|
+
className: "bb-input",
|
|
15385
|
+
placeholder: "paint",
|
|
15386
|
+
value: groupDraft,
|
|
15387
|
+
onChange: (event) => setGroupDraft(event.target.value),
|
|
15388
|
+
onBlur: commitGroup,
|
|
15389
|
+
onKeyDown: (event) => {
|
|
15390
|
+
if (event.key === "Enter") event.currentTarget.blur();
|
|
15391
|
+
}
|
|
15392
|
+
}
|
|
15393
|
+
)
|
|
15394
|
+
] }),
|
|
15395
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "bb-field", children: [
|
|
15396
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("label", { className: "bb-label", children: "Tags" }),
|
|
15397
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
15398
|
+
"input",
|
|
15399
|
+
{
|
|
15400
|
+
className: "bb-input",
|
|
15401
|
+
placeholder: "exterior, configurable",
|
|
15402
|
+
value: tagsDraft,
|
|
15403
|
+
onChange: (event) => setTagsDraft(event.target.value),
|
|
15404
|
+
onBlur: commitTags,
|
|
15405
|
+
onKeyDown: (event) => {
|
|
15406
|
+
if (event.key === "Enter") event.currentTarget.blur();
|
|
15407
|
+
}
|
|
15408
|
+
}
|
|
15409
|
+
)
|
|
15082
15410
|
] })
|
|
15083
15411
|
] }),
|
|
15084
15412
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "bb-checkboxRow", style: { marginTop: 12 }, children: [
|
|
@@ -15129,7 +15457,7 @@ function BasicsPanel({
|
|
|
15129
15457
|
}
|
|
15130
15458
|
|
|
15131
15459
|
// src/components/BindingBuilder/components/ActionsPanel.tsx
|
|
15132
|
-
var
|
|
15460
|
+
var import_react39 = require("react");
|
|
15133
15461
|
|
|
15134
15462
|
// src/components/BindingBuilder/utils/actionCatalog.ts
|
|
15135
15463
|
var ACTION_CATALOG = [
|
|
@@ -15155,19 +15483,19 @@ var ACTION_CATALOG = [
|
|
|
15155
15483
|
id: "toggle-light",
|
|
15156
15484
|
label: "Toggle Light",
|
|
15157
15485
|
handling: "host",
|
|
15158
|
-
description: "Seeded on light bindings.
|
|
15486
|
+
description: "Seeded on light bindings. Add declarative effects for useViewerActions, or handle it in onAction."
|
|
15159
15487
|
},
|
|
15160
15488
|
{
|
|
15161
15489
|
id: "change-light-color",
|
|
15162
15490
|
label: "Change Light Color",
|
|
15163
15491
|
handling: "host",
|
|
15164
|
-
description: "Seeded on light bindings.
|
|
15492
|
+
description: "Seeded on light bindings. Add declarative effects for useViewerActions, or handle it in onAction."
|
|
15165
15493
|
},
|
|
15166
15494
|
{
|
|
15167
15495
|
id: "set-brightness",
|
|
15168
15496
|
label: "Set Brightness",
|
|
15169
15497
|
handling: "host",
|
|
15170
|
-
description: "Seeded on light bindings.
|
|
15498
|
+
description: "Seeded on light bindings. Add declarative effects for useViewerActions, or handle it in onAction."
|
|
15171
15499
|
}
|
|
15172
15500
|
];
|
|
15173
15501
|
var CUSTOM_ACTION_ID = "__custom__";
|
|
@@ -15228,8 +15556,8 @@ function ActionsPanel({
|
|
|
15228
15556
|
onToggle,
|
|
15229
15557
|
updateBinding
|
|
15230
15558
|
}) {
|
|
15231
|
-
const [customRows, setCustomRows] = (0,
|
|
15232
|
-
(0,
|
|
15559
|
+
const [customRows, setCustomRows] = (0, import_react39.useState)(/* @__PURE__ */ new Set());
|
|
15560
|
+
(0, import_react39.useEffect)(() => {
|
|
15233
15561
|
setCustomRows(/* @__PURE__ */ new Set());
|
|
15234
15562
|
}, [selectedItem]);
|
|
15235
15563
|
const actions = selectedBinding.actions ?? [];
|
|
@@ -15345,8 +15673,8 @@ function ActionsPanel({
|
|
|
15345
15673
|
}
|
|
15346
15674
|
)
|
|
15347
15675
|
] }),
|
|
15348
|
-
catalogEntry ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "bb-note", children: catalogEntry.description }) : trimmedId.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "bb-note", style: { color: "#fca5a5" }, children: "An action ID is required
|
|
15349
|
-
"Unrecognised ID
|
|
15676
|
+
catalogEntry ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "bb-note", children: catalogEntry.description }) : trimmedId.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "bb-note", style: { color: "#fca5a5" }, children: "An action ID is required, the button renders but can never be identified in onAction." }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "bb-note", style: { color: "#fcd34d" }, children: [
|
|
15677
|
+
"Unrecognised ID, the viewer has no built-in behavior for it. Add declarative effects and execute them with useViewerActions, or handle it in onAction.",
|
|
15350
15678
|
suggestion ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
15351
15679
|
" Did you mean ",
|
|
15352
15680
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
@@ -15369,7 +15697,13 @@ function ActionsPanel({
|
|
|
15369
15697
|
"?"
|
|
15370
15698
|
] }) : null
|
|
15371
15699
|
] }),
|
|
15372
|
-
|
|
15700
|
+
action.effects?.length ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "bb-note", children: [
|
|
15701
|
+
action.effects.length,
|
|
15702
|
+
" declarative effect",
|
|
15703
|
+
action.effects.length === 1 ? "" : "s",
|
|
15704
|
+
", execute with useViewerActions."
|
|
15705
|
+
] }) : null,
|
|
15706
|
+
isDuplicate ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "bb-note", style: { color: "#fcd34d" }, children: "Another action on this binding uses the same ID, they will render as two identical buttons." }) : null
|
|
15373
15707
|
] }),
|
|
15374
15708
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "bb-actionFooter", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
15375
15709
|
"button",
|
|
@@ -15518,7 +15852,7 @@ function CameraPositionPanel({
|
|
|
15518
15852
|
}
|
|
15519
15853
|
|
|
15520
15854
|
// src/components/BindingBuilder/components/SceneNodesPanel.tsx
|
|
15521
|
-
var
|
|
15855
|
+
var import_react40 = require("react");
|
|
15522
15856
|
|
|
15523
15857
|
// src/components/BindingBuilder/utils/bindingFactory.ts
|
|
15524
15858
|
function slugify2(value) {
|
|
@@ -15607,9 +15941,9 @@ function SceneNodesPanel({
|
|
|
15607
15941
|
isOpen = true,
|
|
15608
15942
|
onToggle
|
|
15609
15943
|
}) {
|
|
15610
|
-
const [search, setSearch] = (0,
|
|
15611
|
-
const nodeKeys = (0,
|
|
15612
|
-
const filteredNodeKeys = (0,
|
|
15944
|
+
const [search, setSearch] = (0, import_react40.useState)("");
|
|
15945
|
+
const nodeKeys = (0, import_react40.useMemo)(() => Object.keys(bindings), [bindings]);
|
|
15946
|
+
const filteredNodeKeys = (0, import_react40.useMemo)(() => {
|
|
15613
15947
|
const query = search.trim().toLowerCase();
|
|
15614
15948
|
if (!query) return nodeKeys;
|
|
15615
15949
|
return nodeKeys.filter((nodeKey) => {
|
|
@@ -15752,7 +16086,7 @@ function mergeAnimationConfig(sceneConfig, animationDetails) {
|
|
|
15752
16086
|
}
|
|
15753
16087
|
|
|
15754
16088
|
// src/components/BindingBuilder/hooks/useUndoableState.ts
|
|
15755
|
-
var
|
|
16089
|
+
var import_react41 = require("react");
|
|
15756
16090
|
var MAX_HISTORY = 100;
|
|
15757
16091
|
function historyReducer(state, action) {
|
|
15758
16092
|
switch (action.type) {
|
|
@@ -15791,13 +16125,13 @@ function historyReducer(state, action) {
|
|
|
15791
16125
|
}
|
|
15792
16126
|
}
|
|
15793
16127
|
function useUndoableState(initial, coalesceWindowMs = 600) {
|
|
15794
|
-
const [state, dispatch] = (0,
|
|
16128
|
+
const [state, dispatch] = (0, import_react41.useReducer)(historyReducer, {
|
|
15795
16129
|
past: [],
|
|
15796
16130
|
present: initial,
|
|
15797
16131
|
future: []
|
|
15798
16132
|
});
|
|
15799
|
-
const lastSetAt = (0,
|
|
15800
|
-
const setValue = (0,
|
|
16133
|
+
const lastSetAt = (0, import_react41.useRef)(0);
|
|
16134
|
+
const setValue = (0, import_react41.useCallback)(
|
|
15801
16135
|
(updater) => {
|
|
15802
16136
|
const now = Date.now();
|
|
15803
16137
|
const coalesce = now - lastSetAt.current < coalesceWindowMs;
|
|
@@ -15806,15 +16140,15 @@ function useUndoableState(initial, coalesceWindowMs = 600) {
|
|
|
15806
16140
|
},
|
|
15807
16141
|
[coalesceWindowMs]
|
|
15808
16142
|
);
|
|
15809
|
-
const undo = (0,
|
|
16143
|
+
const undo = (0, import_react41.useCallback)(() => {
|
|
15810
16144
|
lastSetAt.current = 0;
|
|
15811
16145
|
dispatch({ type: "undo" });
|
|
15812
16146
|
}, []);
|
|
15813
|
-
const redo = (0,
|
|
16147
|
+
const redo = (0, import_react41.useCallback)(() => {
|
|
15814
16148
|
lastSetAt.current = 0;
|
|
15815
16149
|
dispatch({ type: "redo" });
|
|
15816
16150
|
}, []);
|
|
15817
|
-
const reset = (0,
|
|
16151
|
+
const reset = (0, import_react41.useCallback)((value) => {
|
|
15818
16152
|
lastSetAt.current = 0;
|
|
15819
16153
|
dispatch({ type: "reset", value });
|
|
15820
16154
|
}, []);
|
|
@@ -15838,9 +16172,9 @@ function toBindingsJson(bindings) {
|
|
|
15838
16172
|
}
|
|
15839
16173
|
function toBindingsTypeScript(bindings) {
|
|
15840
16174
|
return [
|
|
15841
|
-
'import
|
|
16175
|
+
'import { defineObjectBindings } from "@liveroom-tech/react-immersive";',
|
|
15842
16176
|
"",
|
|
15843
|
-
`export const objectBindings
|
|
16177
|
+
`export const objectBindings = defineObjectBindings(${JSON.stringify(bindings, null, 2)});`,
|
|
15844
16178
|
""
|
|
15845
16179
|
].join("\n");
|
|
15846
16180
|
}
|
|
@@ -16060,30 +16394,30 @@ function mergeSceneConfigSection(current, incoming) {
|
|
|
16060
16394
|
return next;
|
|
16061
16395
|
}
|
|
16062
16396
|
function BindingBuilder({ licenseKey }) {
|
|
16063
|
-
const modelInputRef = (0,
|
|
16064
|
-
const bindingsInputRef = (0,
|
|
16065
|
-
const sceneConfigInputRef = (0,
|
|
16066
|
-
const [modelUrl, setModelUrl] = (0,
|
|
16067
|
-
const [modelName, setModelName] = (0,
|
|
16068
|
-
const [selectedItem, setSelectedItem] = (0,
|
|
16397
|
+
const modelInputRef = (0, import_react42.useRef)(null);
|
|
16398
|
+
const bindingsInputRef = (0, import_react42.useRef)(null);
|
|
16399
|
+
const sceneConfigInputRef = (0, import_react42.useRef)(null);
|
|
16400
|
+
const [modelUrl, setModelUrl] = (0, import_react42.useState)(null);
|
|
16401
|
+
const [modelName, setModelName] = (0, import_react42.useState)("");
|
|
16402
|
+
const [selectedItem, setSelectedItem] = (0, import_react42.useState)(null);
|
|
16069
16403
|
const bindingsHistory = useUndoableState({});
|
|
16070
16404
|
const bindings = bindingsHistory.value;
|
|
16071
16405
|
const setBindings = bindingsHistory.setValue;
|
|
16072
|
-
const [loading, setLoading] = (0,
|
|
16073
|
-
const [isExporting, setIsExporting] = (0,
|
|
16074
|
-
const [statusMessage, setStatusMessage] = (0,
|
|
16406
|
+
const [loading, setLoading] = (0, import_react42.useState)(false);
|
|
16407
|
+
const [isExporting, setIsExporting] = (0, import_react42.useState)(false);
|
|
16408
|
+
const [statusMessage, setStatusMessage] = (0, import_react42.useState)(
|
|
16075
16409
|
"Load the demo model or upload a GLB/GLTF model to generate bindings."
|
|
16076
16410
|
);
|
|
16077
|
-
const [statusTone, setStatusTone] = (0,
|
|
16078
|
-
const [statusBannerVisible, setStatusBannerVisible] = (0,
|
|
16079
|
-
const [metricsDraft, setMetricsDraft] = (0,
|
|
16080
|
-
const [metadataDraft, setMetadataDraft] = (0,
|
|
16081
|
-
const [metricsError, setMetricsError] = (0,
|
|
16082
|
-
const [metadataError, setMetadataError] = (0,
|
|
16083
|
-
const [isPreviewDragActive, setIsPreviewDragActive] = (0,
|
|
16084
|
-
const [isEditorCollapsed, setIsEditorCollapsed] = (0,
|
|
16085
|
-
const [isNodesCollapsed, setIsNodesCollapsed] = (0,
|
|
16086
|
-
const [openObjectSections, setOpenObjectSections] = (0,
|
|
16411
|
+
const [statusTone, setStatusTone] = (0, import_react42.useState)("default");
|
|
16412
|
+
const [statusBannerVisible, setStatusBannerVisible] = (0, import_react42.useState)(false);
|
|
16413
|
+
const [metricsDraft, setMetricsDraft] = (0, import_react42.useState)("{}");
|
|
16414
|
+
const [metadataDraft, setMetadataDraft] = (0, import_react42.useState)("{}");
|
|
16415
|
+
const [metricsError, setMetricsError] = (0, import_react42.useState)(null);
|
|
16416
|
+
const [metadataError, setMetadataError] = (0, import_react42.useState)(null);
|
|
16417
|
+
const [isPreviewDragActive, setIsPreviewDragActive] = (0, import_react42.useState)(false);
|
|
16418
|
+
const [isEditorCollapsed, setIsEditorCollapsed] = (0, import_react42.useState)(false);
|
|
16419
|
+
const [isNodesCollapsed, setIsNodesCollapsed] = (0, import_react42.useState)(false);
|
|
16420
|
+
const [openObjectSections, setOpenObjectSections] = (0, import_react42.useState)({
|
|
16087
16421
|
identity: true,
|
|
16088
16422
|
basics: true,
|
|
16089
16423
|
material: false,
|
|
@@ -16092,7 +16426,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16092
16426
|
metrics: false,
|
|
16093
16427
|
metadata: false
|
|
16094
16428
|
});
|
|
16095
|
-
const [openMaterialPanels, setOpenMaterialPanels] = (0,
|
|
16429
|
+
const [openMaterialPanels, setOpenMaterialPanels] = (0, import_react42.useState)({
|
|
16096
16430
|
pbr: true,
|
|
16097
16431
|
roughness: false,
|
|
16098
16432
|
emission: false,
|
|
@@ -16108,27 +16442,27 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16108
16442
|
});
|
|
16109
16443
|
const toggleObjectSection = (key) => setOpenObjectSections((prev) => ({ ...prev, [key]: !prev[key] }));
|
|
16110
16444
|
const toggleMaterialPanel = (key) => setOpenMaterialPanels((prev) => ({ ...prev, [key]: !prev[key] }));
|
|
16111
|
-
const [activeEditorTab, setActiveEditorTab] = (0,
|
|
16445
|
+
const [activeEditorTab, setActiveEditorTab] = (0, import_react42.useState)(
|
|
16112
16446
|
"object"
|
|
16113
16447
|
);
|
|
16114
|
-
const [activeSubTab, setActiveSubTab] = (0,
|
|
16115
|
-
const [pbrWorkflow, setPbrWorkflow] = (0,
|
|
16116
|
-
const [materialPanelEnabled, setMaterialPanelEnabled] = (0,
|
|
16117
|
-
const materialPanelItemRef = (0,
|
|
16118
|
-
const [zoomOnSelected, setZoomOnSelected] = (0,
|
|
16119
|
-
const [highlightOnHover, setHighlightOnHover] = (0,
|
|
16120
|
-
const [resetDialogOpen, setResetDialogOpen] = (0,
|
|
16121
|
-
const [resetTarget, setResetTarget] = (0,
|
|
16448
|
+
const [activeSubTab, setActiveSubTab] = (0, import_react42.useState)("General");
|
|
16449
|
+
const [pbrWorkflow, setPbrWorkflow] = (0, import_react42.useState)("metalness");
|
|
16450
|
+
const [materialPanelEnabled, setMaterialPanelEnabled] = (0, import_react42.useState)(createMaterialPanelEnabledState());
|
|
16451
|
+
const materialPanelItemRef = (0, import_react42.useRef)(null);
|
|
16452
|
+
const [zoomOnSelected, setZoomOnSelected] = (0, import_react42.useState)(false);
|
|
16453
|
+
const [highlightOnHover, setHighlightOnHover] = (0, import_react42.useState)(true);
|
|
16454
|
+
const [resetDialogOpen, setResetDialogOpen] = (0, import_react42.useState)(false);
|
|
16455
|
+
const [resetTarget, setResetTarget] = (0, import_react42.useState)(
|
|
16122
16456
|
null
|
|
16123
16457
|
);
|
|
16124
16458
|
const sceneConfigHistory = useUndoableState(DEFAULT_SCENE_CONFIG);
|
|
16125
16459
|
const sceneConfig = sceneConfigHistory.value;
|
|
16126
16460
|
const setSceneConfig = sceneConfigHistory.setValue;
|
|
16127
|
-
const [activeAnnotation, setActiveAnnotation] = (0,
|
|
16128
|
-
const [panelHoveredBinding, setPanelHoveredBinding] = (0,
|
|
16461
|
+
const [activeAnnotation, setActiveAnnotation] = (0, import_react42.useState)(null);
|
|
16462
|
+
const [panelHoveredBinding, setPanelHoveredBinding] = (0, import_react42.useState)(null);
|
|
16129
16463
|
const license = useLicense(licenseKey);
|
|
16130
16464
|
const tier = normalizeTier(license.tier);
|
|
16131
|
-
const bindingBuilderContextValue = (0,
|
|
16465
|
+
const bindingBuilderContextValue = (0, import_react42.useMemo)(
|
|
16132
16466
|
() => ({
|
|
16133
16467
|
isInsideEditor: true,
|
|
16134
16468
|
activeTab: activeEditorTab,
|
|
@@ -16139,11 +16473,11 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16139
16473
|
}),
|
|
16140
16474
|
[activeEditorTab, activeSubTab, tier]
|
|
16141
16475
|
);
|
|
16142
|
-
const uploadedModelRef = (0,
|
|
16143
|
-
const previewDragDepthRef = (0,
|
|
16144
|
-
const loadRequestRef = (0,
|
|
16145
|
-
const pendingLoadRef = (0,
|
|
16146
|
-
const loadedSceneRef = (0,
|
|
16476
|
+
const uploadedModelRef = (0, import_react42.useRef)(null);
|
|
16477
|
+
const previewDragDepthRef = (0, import_react42.useRef)(0);
|
|
16478
|
+
const loadRequestRef = (0, import_react42.useRef)(0);
|
|
16479
|
+
const pendingLoadRef = (0, import_react42.useRef)(null);
|
|
16480
|
+
const loadedSceneRef = (0, import_react42.useRef)(null);
|
|
16147
16481
|
const {
|
|
16148
16482
|
cameraState,
|
|
16149
16483
|
resetView,
|
|
@@ -16153,7 +16487,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16153
16487
|
handleCameraChange,
|
|
16154
16488
|
handleViewerReady
|
|
16155
16489
|
} = useViewerCamera();
|
|
16156
|
-
const handlePreviewWaypoint = (0,
|
|
16490
|
+
const handlePreviewWaypoint = (0, import_react42.useCallback)(
|
|
16157
16491
|
(waypoint) => {
|
|
16158
16492
|
setCameraState(
|
|
16159
16493
|
{
|
|
@@ -16177,7 +16511,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16177
16511
|
position: formatVector3(cameraState.position),
|
|
16178
16512
|
target: formatVector3(cameraState.target)
|
|
16179
16513
|
} : null;
|
|
16180
|
-
const handleAnnotationsChange = (0,
|
|
16514
|
+
const handleAnnotationsChange = (0, import_react42.useCallback)(
|
|
16181
16515
|
(newAnnotations) => {
|
|
16182
16516
|
setSceneConfig((prev) => {
|
|
16183
16517
|
const currentIds = prev.annotations.map((a) => a.id).join(",");
|
|
@@ -16193,7 +16527,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16193
16527
|
},
|
|
16194
16528
|
[]
|
|
16195
16529
|
);
|
|
16196
|
-
const handleActiveAnnotationChange = (0,
|
|
16530
|
+
const handleActiveAnnotationChange = (0, import_react42.useCallback)(
|
|
16197
16531
|
(annotation) => {
|
|
16198
16532
|
setActiveAnnotation(
|
|
16199
16533
|
annotation ? {
|
|
@@ -16203,7 +16537,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16203
16537
|
},
|
|
16204
16538
|
[]
|
|
16205
16539
|
);
|
|
16206
|
-
(0,
|
|
16540
|
+
(0, import_react42.useEffect)(() => {
|
|
16207
16541
|
if (!selectedBinding) {
|
|
16208
16542
|
setMetricsDraft("{}");
|
|
16209
16543
|
setMetadataDraft("{}");
|
|
@@ -16216,7 +16550,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16216
16550
|
setMetricsError(null);
|
|
16217
16551
|
setMetadataError(null);
|
|
16218
16552
|
}, [selectedBinding]);
|
|
16219
|
-
(0,
|
|
16553
|
+
(0, import_react42.useEffect)(() => {
|
|
16220
16554
|
const derived = createMaterialPanelEnabledState(selectedMaterial);
|
|
16221
16555
|
if (materialPanelItemRef.current !== selectedItem) {
|
|
16222
16556
|
materialPanelItemRef.current = selectedItem;
|
|
@@ -16235,12 +16569,12 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16235
16569
|
return changed ? next : prev;
|
|
16236
16570
|
});
|
|
16237
16571
|
}, [selectedItem, selectedMaterial]);
|
|
16238
|
-
(0,
|
|
16572
|
+
(0, import_react42.useEffect)(() => {
|
|
16239
16573
|
return () => {
|
|
16240
16574
|
uploadedModelRef.current?.cleanup();
|
|
16241
16575
|
};
|
|
16242
16576
|
}, []);
|
|
16243
|
-
(0,
|
|
16577
|
+
(0, import_react42.useEffect)(() => {
|
|
16244
16578
|
const handleKeyDown = (event) => {
|
|
16245
16579
|
if (event.key.toLowerCase() !== "z" || !(event.metaKey || event.ctrlKey)) {
|
|
16246
16580
|
return;
|
|
@@ -16261,7 +16595,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16261
16595
|
window.addEventListener("keydown", handleKeyDown);
|
|
16262
16596
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
16263
16597
|
}, [activeEditorTab, bindingsHistory, sceneConfigHistory]);
|
|
16264
|
-
(0,
|
|
16598
|
+
(0, import_react42.useEffect)(() => {
|
|
16265
16599
|
if (loading || statusTone === "default" || statusTone === "success") return;
|
|
16266
16600
|
setStatusBannerVisible(true);
|
|
16267
16601
|
const timeout = window.setTimeout(
|
|
@@ -16270,8 +16604,8 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16270
16604
|
);
|
|
16271
16605
|
return () => window.clearTimeout(timeout);
|
|
16272
16606
|
}, [statusMessage, statusTone, loading]);
|
|
16273
|
-
const nodeKeys = (0,
|
|
16274
|
-
const idError = (0,
|
|
16607
|
+
const nodeKeys = (0, import_react42.useMemo)(() => Object.keys(bindings), [bindings]);
|
|
16608
|
+
const idError = (0, import_react42.useMemo)(() => {
|
|
16275
16609
|
if (!selectedItem || !selectedBinding) return null;
|
|
16276
16610
|
const trimmed = selectedBinding.id.trim();
|
|
16277
16611
|
if (!trimmed) return "ID is required.";
|
|
@@ -16314,7 +16648,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16314
16648
|
});
|
|
16315
16649
|
}
|
|
16316
16650
|
};
|
|
16317
|
-
const applyBindingsFromScene = (0,
|
|
16651
|
+
const applyBindingsFromScene = (0, import_react42.useCallback)(
|
|
16318
16652
|
(scene, nextModelName) => {
|
|
16319
16653
|
const nodeNames = collectNodeNames(scene);
|
|
16320
16654
|
bindingsHistory.reset(buildBindingsFromNodes(nodeNames));
|
|
@@ -16353,7 +16687,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16353
16687
|
bindingsHistory.reset({});
|
|
16354
16688
|
setSelectedItem(null);
|
|
16355
16689
|
};
|
|
16356
|
-
const handleViewerModelLoaded = (0,
|
|
16690
|
+
const handleViewerModelLoaded = (0, import_react42.useCallback)(
|
|
16357
16691
|
(scene) => {
|
|
16358
16692
|
const pending = pendingLoadRef.current;
|
|
16359
16693
|
if (!pending || pending.requestId !== loadRequestRef.current) return;
|
|
@@ -16363,7 +16697,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16363
16697
|
},
|
|
16364
16698
|
[applyBindingsFromScene]
|
|
16365
16699
|
);
|
|
16366
|
-
const handleViewerLoadError = (0,
|
|
16700
|
+
const handleViewerLoadError = (0, import_react42.useCallback)((error) => {
|
|
16367
16701
|
const pending = pendingLoadRef.current;
|
|
16368
16702
|
if (!pending || pending.requestId !== loadRequestRef.current) return;
|
|
16369
16703
|
pendingLoadRef.current = null;
|
|
@@ -16374,7 +16708,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16374
16708
|
setStatusTone("error");
|
|
16375
16709
|
setLoading(false);
|
|
16376
16710
|
}, []);
|
|
16377
|
-
const handleAnimationsReady = (0,
|
|
16711
|
+
const handleAnimationsReady = (0, import_react42.useCallback)(
|
|
16378
16712
|
(controls) => {
|
|
16379
16713
|
viewerAnimations.handleAnimationsReady(controls);
|
|
16380
16714
|
const details = controls.clipDetails ?? controls.clips.map((sourceName) => ({ sourceName, duration: 0 }));
|
|
@@ -16675,7 +17009,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16675
17009
|
}));
|
|
16676
17010
|
setError(null);
|
|
16677
17011
|
};
|
|
16678
|
-
const handleViewerSelect = (0,
|
|
17012
|
+
const handleViewerSelect = (0, import_react42.useCallback)(
|
|
16679
17013
|
(binding) => {
|
|
16680
17014
|
if (!binding) {
|
|
16681
17015
|
setSelectedItem(null);
|
|
@@ -16688,7 +17022,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16688
17022
|
},
|
|
16689
17023
|
[bindings]
|
|
16690
17024
|
);
|
|
16691
|
-
const handleSceneNodeSelect = (0,
|
|
17025
|
+
const handleSceneNodeSelect = (0, import_react42.useCallback)(
|
|
16692
17026
|
async (nodeKey) => {
|
|
16693
17027
|
setSelectedItem(nodeKey);
|
|
16694
17028
|
setPanelHoveredBinding(null);
|
|
@@ -16696,7 +17030,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16696
17030
|
},
|
|
16697
17031
|
[focusObject]
|
|
16698
17032
|
);
|
|
16699
|
-
const saveCameraPositionForSelectedObject = (0,
|
|
17033
|
+
const saveCameraPositionForSelectedObject = (0, import_react42.useCallback)(() => {
|
|
16700
17034
|
if (!selectedItem || !cameraState) {
|
|
16701
17035
|
return;
|
|
16702
17036
|
}
|
|
@@ -16711,7 +17045,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16711
17045
|
cameraState: currentCameraState
|
|
16712
17046
|
}));
|
|
16713
17047
|
}, [selectedItem, cameraState]);
|
|
16714
|
-
const goToSavedCameraPosition = (0,
|
|
17048
|
+
const goToSavedCameraPosition = (0, import_react42.useCallback)(() => {
|
|
16715
17049
|
if (!savedCameraPosition?.position || !savedCameraPosition?.target) return;
|
|
16716
17050
|
setCameraState(
|
|
16717
17051
|
{
|
|
@@ -16723,28 +17057,28 @@ function BindingBuilder({ licenseKey }) {
|
|
|
16723
17057
|
true
|
|
16724
17058
|
);
|
|
16725
17059
|
}, [savedCameraPosition, setCameraState, cameraState]);
|
|
16726
|
-
const clearSavedCameraPosition = (0,
|
|
17060
|
+
const clearSavedCameraPosition = (0, import_react42.useCallback)(() => {
|
|
16727
17061
|
if (!selectedItem) return;
|
|
16728
17062
|
updateBinding(selectedItem, (binding) => ({
|
|
16729
17063
|
...binding,
|
|
16730
17064
|
cameraState: void 0
|
|
16731
17065
|
}));
|
|
16732
17066
|
}, [selectedItem]);
|
|
16733
|
-
const handleResetView = (0,
|
|
17067
|
+
const handleResetView = (0, import_react42.useCallback)(async () => {
|
|
16734
17068
|
await resetView();
|
|
16735
17069
|
}, [resetView]);
|
|
16736
|
-
const handleFitScene = (0,
|
|
17070
|
+
const handleFitScene = (0, import_react42.useCallback)(async () => {
|
|
16737
17071
|
await fitScene();
|
|
16738
17072
|
}, [fitScene]);
|
|
16739
|
-
const openResetDialog = (0,
|
|
17073
|
+
const openResetDialog = (0, import_react42.useCallback)((target) => {
|
|
16740
17074
|
setResetTarget(target);
|
|
16741
17075
|
setResetDialogOpen(true);
|
|
16742
17076
|
}, []);
|
|
16743
|
-
const closeResetDialog = (0,
|
|
17077
|
+
const closeResetDialog = (0, import_react42.useCallback)(() => {
|
|
16744
17078
|
setResetDialogOpen(false);
|
|
16745
17079
|
setResetTarget(null);
|
|
16746
17080
|
}, []);
|
|
16747
|
-
const executeReset = (0,
|
|
17081
|
+
const executeReset = (0, import_react42.useCallback)(() => {
|
|
16748
17082
|
if (resetTarget === "bindings") {
|
|
16749
17083
|
if (!nodeKeys.length) {
|
|
16750
17084
|
closeResetDialog();
|
|
@@ -17291,7 +17625,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
17291
17625
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("strong", { children: resetTarget === "bindings" ? "Object Bindings" : "Scene Config" }),
|
|
17292
17626
|
"?"
|
|
17293
17627
|
] }),
|
|
17294
|
-
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "bb-reset-details", children: resetTarget === "bindings" ? "This will remove all your custom changes to object properties, materials, actions, camera positions, metrics, and metadata." : "This will restore all scene settings (camera, lighting, environment, background, animations, annotations, etc.) to their default values." }),
|
|
17628
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "bb-reset-details", children: resetTarget === "bindings" ? "This will remove all your custom changes to object properties, groups, tags, transforms, materials, actions, camera positions, metrics, and metadata." : "This will restore all scene settings (camera, lighting, environment, background, animations, annotations, etc.) to their default values." }),
|
|
17295
17629
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "bb-reset-warning", children: "This action cannot be undone!" })
|
|
17296
17630
|
] }),
|
|
17297
17631
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "bb-reset-footer", children: [
|
|
@@ -17303,11 +17637,11 @@ function BindingBuilder({ licenseKey }) {
|
|
|
17303
17637
|
}
|
|
17304
17638
|
|
|
17305
17639
|
// src/components/SimpleModelViewer/SimpleModelViewer.tsx
|
|
17306
|
-
var
|
|
17640
|
+
var import_react43 = require("react");
|
|
17307
17641
|
var import_drei7 = require("@react-three/drei");
|
|
17308
17642
|
var import_fiber13 = require("@react-three/fiber");
|
|
17309
17643
|
var import_fiber14 = require("@react-three/fiber");
|
|
17310
|
-
var
|
|
17644
|
+
var import_three23 = require("three");
|
|
17311
17645
|
var import_three_stdlib4 = require("three-stdlib");
|
|
17312
17646
|
|
|
17313
17647
|
// src/styles/SimpleModelViewer.css
|
|
@@ -17335,15 +17669,15 @@ function isMeshNode2(o) {
|
|
|
17335
17669
|
function applyClippingPlanes(scene, controls) {
|
|
17336
17670
|
if (!controls) return;
|
|
17337
17671
|
const camera = controls.camera;
|
|
17338
|
-
if (!(camera instanceof
|
|
17339
|
-
const size = new
|
|
17672
|
+
if (!(camera instanceof import_three23.PerspectiveCamera)) return;
|
|
17673
|
+
const size = new import_three23.Box3().setFromObject(scene).getSize(new import_three23.Vector3()).length();
|
|
17340
17674
|
if (!Number.isFinite(size) || size <= 0) return;
|
|
17341
17675
|
camera.near = size / 100;
|
|
17342
17676
|
camera.far = size * 100;
|
|
17343
17677
|
camera.updateProjectionMatrix();
|
|
17344
17678
|
controls.maxDistance = size * 10;
|
|
17345
17679
|
}
|
|
17346
|
-
var ModelErrorBoundary2 = class extends
|
|
17680
|
+
var ModelErrorBoundary2 = class extends import_react43.Component {
|
|
17347
17681
|
constructor() {
|
|
17348
17682
|
super(...arguments);
|
|
17349
17683
|
this.state = { hasError: false };
|
|
@@ -17375,12 +17709,12 @@ function InnerModel({
|
|
|
17375
17709
|
meshopt: true
|
|
17376
17710
|
});
|
|
17377
17711
|
const invalidate = (0, import_fiber13.useThree)((state) => state.invalidate);
|
|
17378
|
-
const [hoveredKey, setHoveredKey] = (0,
|
|
17379
|
-
const scene = (0,
|
|
17712
|
+
const [hoveredKey, setHoveredKey] = (0, import_react43.useState)(null);
|
|
17713
|
+
const scene = (0, import_react43.useMemo)(
|
|
17380
17714
|
() => import_three_stdlib4.SkeletonUtils.clone(rawScene),
|
|
17381
17715
|
[rawScene]
|
|
17382
17716
|
);
|
|
17383
|
-
const meshMap = (0,
|
|
17717
|
+
const meshMap = (0, import_react43.useMemo)(() => {
|
|
17384
17718
|
const map = {};
|
|
17385
17719
|
scene.traverse((obj) => {
|
|
17386
17720
|
if (!isMeshNode2(obj)) return;
|
|
@@ -17389,7 +17723,7 @@ function InnerModel({
|
|
|
17389
17723
|
});
|
|
17390
17724
|
return map;
|
|
17391
17725
|
}, [scene]);
|
|
17392
|
-
const perKeyMaterials = (0,
|
|
17726
|
+
const perKeyMaterials = (0, import_react43.useMemo)(() => {
|
|
17393
17727
|
const map = {};
|
|
17394
17728
|
for (const [key, { ref }] of Object.entries(meshMap)) {
|
|
17395
17729
|
const original = Array.isArray(ref.material) ? ref.material[0] : ref.material;
|
|
@@ -17405,14 +17739,14 @@ function InnerModel({
|
|
|
17405
17739
|
}
|
|
17406
17740
|
return map;
|
|
17407
17741
|
}, [meshMap]);
|
|
17408
|
-
(0,
|
|
17742
|
+
(0, import_react43.useEffect)(
|
|
17409
17743
|
() => () => {
|
|
17410
17744
|
Object.values(perKeyMaterials).forEach((m) => m.dispose());
|
|
17411
17745
|
},
|
|
17412
17746
|
[perKeyMaterials]
|
|
17413
17747
|
);
|
|
17414
|
-
const notifiedUrl = (0,
|
|
17415
|
-
(0,
|
|
17748
|
+
const notifiedUrl = (0, import_react43.useRef)(null);
|
|
17749
|
+
(0, import_react43.useEffect)(() => {
|
|
17416
17750
|
if (notifiedUrl.current === url) return;
|
|
17417
17751
|
notifiedUrl.current = url;
|
|
17418
17752
|
scene.updateWorldMatrix(true, true);
|
|
@@ -17420,7 +17754,7 @@ function InnerModel({
|
|
|
17420
17754
|
onMeshesReady(meshMap);
|
|
17421
17755
|
onModelLoaded(scene);
|
|
17422
17756
|
}, [url, scene, meshMap, onMeshesReady, onModelLoaded]);
|
|
17423
|
-
(0,
|
|
17757
|
+
(0, import_react43.useEffect)(() => {
|
|
17424
17758
|
const controller = new AbortController();
|
|
17425
17759
|
void buildSceneBVH(scene, controller.signal);
|
|
17426
17760
|
return () => {
|
|
@@ -17428,26 +17762,26 @@ function InnerModel({
|
|
|
17428
17762
|
disposeSceneBVH(scene);
|
|
17429
17763
|
};
|
|
17430
17764
|
}, [scene]);
|
|
17431
|
-
const pointerRaycastEnabled = (0,
|
|
17765
|
+
const pointerRaycastEnabled = (0, import_react43.useMemo)(
|
|
17432
17766
|
() => !exceedsBvhBudget(scene),
|
|
17433
17767
|
[scene]
|
|
17434
17768
|
);
|
|
17435
|
-
(0,
|
|
17769
|
+
(0, import_react43.useEffect)(() => {
|
|
17436
17770
|
for (const [key, { ref }] of Object.entries(meshMap)) {
|
|
17437
17771
|
nodeRefsOut.current[key] = ref;
|
|
17438
17772
|
}
|
|
17439
17773
|
}, [meshMap, nodeRefsOut]);
|
|
17440
|
-
(0,
|
|
17774
|
+
(0, import_react43.useEffect)(() => {
|
|
17441
17775
|
if (!highlightOnHover && hoveredKey !== null) {
|
|
17442
17776
|
setHoveredKey(null);
|
|
17443
17777
|
}
|
|
17444
17778
|
}, [highlightOnHover, hoveredKey]);
|
|
17445
|
-
(0,
|
|
17779
|
+
(0, import_react43.useEffect)(() => {
|
|
17446
17780
|
return () => {
|
|
17447
17781
|
document.body.style.cursor = "default";
|
|
17448
17782
|
};
|
|
17449
17783
|
}, []);
|
|
17450
|
-
(0,
|
|
17784
|
+
(0, import_react43.useEffect)(() => {
|
|
17451
17785
|
for (const [key, { ref }] of Object.entries(meshMap)) {
|
|
17452
17786
|
ref.visible = !hiddenKeys.has(key);
|
|
17453
17787
|
const mat = perKeyMaterials[key];
|
|
@@ -17517,11 +17851,11 @@ function CameraFitter({
|
|
|
17517
17851
|
refitOnResize,
|
|
17518
17852
|
onInitialFitComplete
|
|
17519
17853
|
}) {
|
|
17520
|
-
const fitted = (0,
|
|
17854
|
+
const fitted = (0, import_react43.useRef)(false);
|
|
17521
17855
|
const invalidate = (0, import_fiber13.useThree)((state) => state.invalidate);
|
|
17522
17856
|
const size = (0, import_fiber13.useThree)((state) => state.size);
|
|
17523
|
-
const resizeTimerRef = (0,
|
|
17524
|
-
(0,
|
|
17857
|
+
const resizeTimerRef = (0, import_react43.useRef)(null);
|
|
17858
|
+
(0, import_react43.useEffect)(() => {
|
|
17525
17859
|
fitted.current = false;
|
|
17526
17860
|
invalidate();
|
|
17527
17861
|
}, [invalidate, scene]);
|
|
@@ -17541,7 +17875,7 @@ function CameraFitter({
|
|
|
17541
17875
|
}).catch(() => {
|
|
17542
17876
|
}).finally(onInitialFitComplete);
|
|
17543
17877
|
});
|
|
17544
|
-
(0,
|
|
17878
|
+
(0, import_react43.useEffect)(() => {
|
|
17545
17879
|
if (!refitOnResize || !fitted.current || !scene || !controlsRef.current) {
|
|
17546
17880
|
return;
|
|
17547
17881
|
}
|
|
@@ -17569,7 +17903,7 @@ function CameraFitter({
|
|
|
17569
17903
|
function ExposureController({ exposure }) {
|
|
17570
17904
|
const gl = (0, import_fiber13.useThree)((state) => state.gl);
|
|
17571
17905
|
const invalidate = (0, import_fiber13.useThree)((state) => state.invalidate);
|
|
17572
|
-
(0,
|
|
17906
|
+
(0, import_react43.useEffect)(() => {
|
|
17573
17907
|
gl.toneMappingExposure = exposure;
|
|
17574
17908
|
invalidate();
|
|
17575
17909
|
}, [gl, exposure, invalidate]);
|
|
@@ -17677,7 +18011,7 @@ function EnvironmentSection({
|
|
|
17677
18011
|
title,
|
|
17678
18012
|
children
|
|
17679
18013
|
}) {
|
|
17680
|
-
const [collapsed, setCollapsed] = (0,
|
|
18014
|
+
const [collapsed, setCollapsed] = (0, import_react43.useState)(false);
|
|
17681
18015
|
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "env-section", children: [
|
|
17682
18016
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
17683
18017
|
"button",
|
|
@@ -17842,8 +18176,8 @@ function SceneObjectsPanel2({
|
|
|
17842
18176
|
onHover,
|
|
17843
18177
|
onToggleVisibility
|
|
17844
18178
|
}) {
|
|
17845
|
-
const [search, setSearch] = (0,
|
|
17846
|
-
const [rowHovered, setRowHovered] = (0,
|
|
18179
|
+
const [search, setSearch] = (0, import_react43.useState)("");
|
|
18180
|
+
const [rowHovered, setRowHovered] = (0, import_react43.useState)(null);
|
|
17847
18181
|
const entries = Object.values(meshKeys).filter(
|
|
17848
18182
|
(m) => m.label.toLowerCase().includes(search.toLowerCase())
|
|
17849
18183
|
);
|
|
@@ -17967,35 +18301,35 @@ function SimpleModelViewer({
|
|
|
17967
18301
|
onModelLoaded,
|
|
17968
18302
|
onLoadError
|
|
17969
18303
|
}) {
|
|
17970
|
-
const cameraControlsRef = (0,
|
|
17971
|
-
const nodeRefsOut = (0,
|
|
17972
|
-
const fileInputRef = (0,
|
|
17973
|
-
const uploadedModelRef = (0,
|
|
17974
|
-
const dragDepthRef = (0,
|
|
17975
|
-
const [loadedScene, setLoadedScene] = (0,
|
|
17976
|
-
const [largeModelTriangles, setLargeModelTriangles] = (0,
|
|
18304
|
+
const cameraControlsRef = (0, import_react43.useRef)(null);
|
|
18305
|
+
const nodeRefsOut = (0, import_react43.useRef)({});
|
|
18306
|
+
const fileInputRef = (0, import_react43.useRef)(null);
|
|
18307
|
+
const uploadedModelRef = (0, import_react43.useRef)(null);
|
|
18308
|
+
const dragDepthRef = (0, import_react43.useRef)(0);
|
|
18309
|
+
const [loadedScene, setLoadedScene] = (0, import_react43.useState)(null);
|
|
18310
|
+
const [largeModelTriangles, setLargeModelTriangles] = (0, import_react43.useState)(
|
|
17977
18311
|
null
|
|
17978
18312
|
);
|
|
17979
|
-
const [largeModelNoticeDismissed, setLargeModelNoticeDismissed] = (0,
|
|
17980
|
-
const [meshKeys, setMeshKeys] = (0,
|
|
17981
|
-
const [hiddenKeys, setHiddenKeys] = (0,
|
|
17982
|
-
const [selectedKey, setSelectedKey] = (0,
|
|
17983
|
-
const [panelHoveredKey, setPanelHoveredKey] = (0,
|
|
17984
|
-
const [uploadedModelUrl, setUploadedModelUrl] = (0,
|
|
17985
|
-
const [uploadedModelName, setUploadedModelName] = (0,
|
|
18313
|
+
const [largeModelNoticeDismissed, setLargeModelNoticeDismissed] = (0, import_react43.useState)(false);
|
|
18314
|
+
const [meshKeys, setMeshKeys] = (0, import_react43.useState)({});
|
|
18315
|
+
const [hiddenKeys, setHiddenKeys] = (0, import_react43.useState)(/* @__PURE__ */ new Set());
|
|
18316
|
+
const [selectedKey, setSelectedKey] = (0, import_react43.useState)(null);
|
|
18317
|
+
const [panelHoveredKey, setPanelHoveredKey] = (0, import_react43.useState)(null);
|
|
18318
|
+
const [uploadedModelUrl, setUploadedModelUrl] = (0, import_react43.useState)(null);
|
|
18319
|
+
const [uploadedModelName, setUploadedModelName] = (0, import_react43.useState)(
|
|
17986
18320
|
null
|
|
17987
18321
|
);
|
|
17988
|
-
const [modelLoadFailed, setModelLoadFailed] = (0,
|
|
17989
|
-
const [isResolvingUpload, setIsResolvingUpload] = (0,
|
|
17990
|
-
const [initialFitComplete, setInitialFitComplete] = (0,
|
|
17991
|
-
const [isDragActive, setIsDragActive] = (0,
|
|
17992
|
-
const [isPanelOpen, setIsPanelOpen] = (0,
|
|
18322
|
+
const [modelLoadFailed, setModelLoadFailed] = (0, import_react43.useState)(false);
|
|
18323
|
+
const [isResolvingUpload, setIsResolvingUpload] = (0, import_react43.useState)(false);
|
|
18324
|
+
const [initialFitComplete, setInitialFitComplete] = (0, import_react43.useState)(false);
|
|
18325
|
+
const [isDragActive, setIsDragActive] = (0, import_react43.useState)(false);
|
|
18326
|
+
const [isPanelOpen, setIsPanelOpen] = (0, import_react43.useState)(
|
|
17993
18327
|
() => typeof window === "undefined" ? true : window.innerWidth > 900
|
|
17994
18328
|
);
|
|
17995
|
-
const [isEnvPanelOpen, setIsEnvPanelOpen] = (0,
|
|
18329
|
+
const [isEnvPanelOpen, setIsEnvPanelOpen] = (0, import_react43.useState)(
|
|
17996
18330
|
() => typeof window === "undefined" ? true : window.innerWidth > 900
|
|
17997
18331
|
);
|
|
17998
|
-
const [envSettings, setEnvSettings] = (0,
|
|
18332
|
+
const [envSettings, setEnvSettings] = (0, import_react43.useState)({
|
|
17999
18333
|
backgroundEnabled,
|
|
18000
18334
|
backgroundColor,
|
|
18001
18335
|
autoRotate,
|
|
@@ -18007,7 +18341,7 @@ function SimpleModelViewer({
|
|
|
18007
18341
|
directionalColor
|
|
18008
18342
|
});
|
|
18009
18343
|
const activeModelUrl = enableModelUpload ? uploadedModelUrl : modelUrl;
|
|
18010
|
-
const resetModelState = (0,
|
|
18344
|
+
const resetModelState = (0, import_react43.useCallback)(() => {
|
|
18011
18345
|
setLoadedScene(null);
|
|
18012
18346
|
setLargeModelTriangles(null);
|
|
18013
18347
|
setLargeModelNoticeDismissed(false);
|
|
@@ -18018,11 +18352,11 @@ function SimpleModelViewer({
|
|
|
18018
18352
|
setModelLoadFailed(false);
|
|
18019
18353
|
setInitialFitComplete(false);
|
|
18020
18354
|
}, []);
|
|
18021
|
-
const revokeUploadedModelUrl = (0,
|
|
18355
|
+
const revokeUploadedModelUrl = (0, import_react43.useCallback)(() => {
|
|
18022
18356
|
uploadedModelRef.current?.cleanup();
|
|
18023
18357
|
uploadedModelRef.current = null;
|
|
18024
18358
|
}, []);
|
|
18025
|
-
const clearUploadedModel = (0,
|
|
18359
|
+
const clearUploadedModel = (0, import_react43.useCallback)(() => {
|
|
18026
18360
|
revokeUploadedModelUrl();
|
|
18027
18361
|
setUploadedModelUrl(null);
|
|
18028
18362
|
setUploadedModelName(null);
|
|
@@ -18051,7 +18385,7 @@ function SimpleModelViewer({
|
|
|
18051
18385
|
resetModelState,
|
|
18052
18386
|
revokeUploadedModelUrl
|
|
18053
18387
|
]);
|
|
18054
|
-
const handleUploadedModel = (0,
|
|
18388
|
+
const handleUploadedModel = (0, import_react43.useCallback)(
|
|
18055
18389
|
async (file) => {
|
|
18056
18390
|
setIsResolvingUpload(true);
|
|
18057
18391
|
try {
|
|
@@ -18070,7 +18404,7 @@ function SimpleModelViewer({
|
|
|
18070
18404
|
},
|
|
18071
18405
|
[onLoadError, resetModelState, revokeUploadedModelUrl]
|
|
18072
18406
|
);
|
|
18073
|
-
const handleFileSelection = (0,
|
|
18407
|
+
const handleFileSelection = (0, import_react43.useCallback)(
|
|
18074
18408
|
(files) => {
|
|
18075
18409
|
const file = files?.[0];
|
|
18076
18410
|
if (!file) return;
|
|
@@ -18078,29 +18412,29 @@ function SimpleModelViewer({
|
|
|
18078
18412
|
},
|
|
18079
18413
|
[handleUploadedModel]
|
|
18080
18414
|
);
|
|
18081
|
-
(0,
|
|
18415
|
+
(0, import_react43.useEffect)(() => {
|
|
18082
18416
|
return () => {
|
|
18083
18417
|
revokeUploadedModelUrl();
|
|
18084
18418
|
};
|
|
18085
18419
|
}, [revokeUploadedModelUrl]);
|
|
18086
|
-
const handleEnvSettingChange = (0,
|
|
18420
|
+
const handleEnvSettingChange = (0, import_react43.useCallback)(
|
|
18087
18421
|
(key, value) => {
|
|
18088
18422
|
setEnvSettings((prev) => ({ ...prev, [key]: value }));
|
|
18089
18423
|
},
|
|
18090
18424
|
[]
|
|
18091
18425
|
);
|
|
18092
|
-
(0,
|
|
18426
|
+
(0, import_react43.useEffect)(() => {
|
|
18093
18427
|
setEnvSettings((prev) => ({ ...prev, backgroundColor }));
|
|
18094
18428
|
}, [backgroundColor]);
|
|
18095
|
-
(0,
|
|
18429
|
+
(0, import_react43.useEffect)(() => {
|
|
18096
18430
|
resetModelState();
|
|
18097
18431
|
}, [activeModelUrl, resetModelState]);
|
|
18098
|
-
const handleMeshesReady = (0,
|
|
18432
|
+
const handleMeshesReady = (0, import_react43.useCallback)((meshes) => {
|
|
18099
18433
|
setMeshKeys(meshes);
|
|
18100
18434
|
setHiddenKeys(/* @__PURE__ */ new Set());
|
|
18101
18435
|
setSelectedKey(null);
|
|
18102
18436
|
}, []);
|
|
18103
|
-
const handleModelLoaded = (0,
|
|
18437
|
+
const handleModelLoaded = (0, import_react43.useCallback)(
|
|
18104
18438
|
(scene) => {
|
|
18105
18439
|
setLoadedScene(scene);
|
|
18106
18440
|
setModelLoadFailed(false);
|
|
@@ -18111,14 +18445,14 @@ function SimpleModelViewer({
|
|
|
18111
18445
|
},
|
|
18112
18446
|
[onModelLoaded]
|
|
18113
18447
|
);
|
|
18114
|
-
const handleLoadError = (0,
|
|
18448
|
+
const handleLoadError = (0, import_react43.useCallback)(
|
|
18115
18449
|
(error) => {
|
|
18116
18450
|
setModelLoadFailed(true);
|
|
18117
18451
|
onLoadError?.(error);
|
|
18118
18452
|
},
|
|
18119
18453
|
[onLoadError]
|
|
18120
18454
|
);
|
|
18121
|
-
const focusMesh = (0,
|
|
18455
|
+
const focusMesh = (0, import_react43.useCallback)(
|
|
18122
18456
|
(key) => {
|
|
18123
18457
|
setSelectedKey(key);
|
|
18124
18458
|
if (!zoomOnSelected) return;
|
|
@@ -18134,14 +18468,14 @@ function SimpleModelViewer({
|
|
|
18134
18468
|
},
|
|
18135
18469
|
[zoomOnSelected]
|
|
18136
18470
|
);
|
|
18137
|
-
const handleToggleVisibility = (0,
|
|
18471
|
+
const handleToggleVisibility = (0, import_react43.useCallback)((key) => {
|
|
18138
18472
|
setHiddenKeys((prev) => {
|
|
18139
18473
|
const next = new Set(prev);
|
|
18140
18474
|
next.has(key) ? next.delete(key) : next.add(key);
|
|
18141
18475
|
return next;
|
|
18142
18476
|
});
|
|
18143
18477
|
}, []);
|
|
18144
|
-
const handleDragEnter = (0,
|
|
18478
|
+
const handleDragEnter = (0, import_react43.useCallback)(
|
|
18145
18479
|
(event) => {
|
|
18146
18480
|
if (!enableModelUpload || !supportsDraggedFiles(event.dataTransfer)) {
|
|
18147
18481
|
return;
|
|
@@ -18153,7 +18487,7 @@ function SimpleModelViewer({
|
|
|
18153
18487
|
},
|
|
18154
18488
|
[enableModelUpload]
|
|
18155
18489
|
);
|
|
18156
|
-
const handleDragOver = (0,
|
|
18490
|
+
const handleDragOver = (0, import_react43.useCallback)(
|
|
18157
18491
|
(event) => {
|
|
18158
18492
|
if (!enableModelUpload || !supportsDraggedFiles(event.dataTransfer)) {
|
|
18159
18493
|
return;
|
|
@@ -18165,7 +18499,7 @@ function SimpleModelViewer({
|
|
|
18165
18499
|
},
|
|
18166
18500
|
[enableModelUpload]
|
|
18167
18501
|
);
|
|
18168
|
-
const handleDragLeave = (0,
|
|
18502
|
+
const handleDragLeave = (0, import_react43.useCallback)(
|
|
18169
18503
|
(event) => {
|
|
18170
18504
|
if (!enableModelUpload || !supportsDraggedFiles(event.dataTransfer)) {
|
|
18171
18505
|
return;
|
|
@@ -18179,7 +18513,7 @@ function SimpleModelViewer({
|
|
|
18179
18513
|
},
|
|
18180
18514
|
[enableModelUpload]
|
|
18181
18515
|
);
|
|
18182
|
-
const handleDrop = (0,
|
|
18516
|
+
const handleDrop = (0, import_react43.useCallback)(
|
|
18183
18517
|
(event) => {
|
|
18184
18518
|
if (!enableModelUpload || !supportsDraggedFiles(event.dataTransfer)) {
|
|
18185
18519
|
return;
|
|
@@ -18272,7 +18606,7 @@ function SimpleModelViewer({
|
|
|
18272
18606
|
raycaster: { firstHitOnly: true },
|
|
18273
18607
|
style: { background: envSettings.backgroundColor },
|
|
18274
18608
|
camera: { position: [0, 0, 5], fov: 45, near: 0.1, far: 1e3 },
|
|
18275
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
18609
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react43.Suspense, { fallback: null, children: [
|
|
18276
18610
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
18277
18611
|
"ambientLight",
|
|
18278
18612
|
{
|
|
@@ -18290,7 +18624,7 @@ function SimpleModelViewer({
|
|
|
18290
18624
|
}
|
|
18291
18625
|
),
|
|
18292
18626
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("directionalLight", { position: [-5, 5, 5], intensity: 0.5 }),
|
|
18293
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
18627
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react43.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
18294
18628
|
import_drei7.Environment,
|
|
18295
18629
|
{
|
|
18296
18630
|
preset: envSettings.envPreset,
|
|
@@ -18309,7 +18643,7 @@ function SimpleModelViewer({
|
|
|
18309
18643
|
ModelErrorBoundary2,
|
|
18310
18644
|
{
|
|
18311
18645
|
onLoadError: handleLoadError,
|
|
18312
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
18646
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react43.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
18313
18647
|
InnerModel,
|
|
18314
18648
|
{
|
|
18315
18649
|
url: activeModelUrl,
|
|
@@ -18408,18 +18742,18 @@ function SimpleModelViewer({
|
|
|
18408
18742
|
}
|
|
18409
18743
|
|
|
18410
18744
|
// src/hooks/useViewerSelection.ts
|
|
18411
|
-
var
|
|
18745
|
+
var import_react44 = require("react");
|
|
18412
18746
|
function useViewerSelection(initialSelectedObjectBinding = null) {
|
|
18413
|
-
const [selectedObjectBinding, setSelectedObjectBinding] = (0,
|
|
18747
|
+
const [selectedObjectBinding, setSelectedObjectBinding] = (0, import_react44.useState)(
|
|
18414
18748
|
initialSelectedObjectBinding
|
|
18415
18749
|
);
|
|
18416
|
-
const handleObjectSelect = (0,
|
|
18750
|
+
const handleObjectSelect = (0, import_react44.useCallback)(
|
|
18417
18751
|
(binding) => {
|
|
18418
18752
|
setSelectedObjectBinding(binding);
|
|
18419
18753
|
},
|
|
18420
18754
|
[setSelectedObjectBinding]
|
|
18421
18755
|
);
|
|
18422
|
-
const clearSelection = (0,
|
|
18756
|
+
const clearSelection = (0, import_react44.useCallback)(() => {
|
|
18423
18757
|
setSelectedObjectBinding(null);
|
|
18424
18758
|
}, []);
|
|
18425
18759
|
return {
|
|
@@ -18431,9 +18765,9 @@ function useViewerSelection(initialSelectedObjectBinding = null) {
|
|
|
18431
18765
|
}
|
|
18432
18766
|
|
|
18433
18767
|
// src/hooks/useObjectBinding.ts
|
|
18434
|
-
var
|
|
18768
|
+
var import_react45 = require("react");
|
|
18435
18769
|
function useObjectBinding(objectBindings, objectId) {
|
|
18436
|
-
return (0,
|
|
18770
|
+
return (0, import_react45.useMemo)(() => {
|
|
18437
18771
|
if (!objectId) {
|
|
18438
18772
|
return null;
|
|
18439
18773
|
}
|
|
@@ -18448,16 +18782,16 @@ function useObjectBinding(objectBindings, objectId) {
|
|
|
18448
18782
|
}
|
|
18449
18783
|
|
|
18450
18784
|
// src/hooks/useObjectBindingIds.ts
|
|
18451
|
-
var
|
|
18785
|
+
var import_react46 = require("react");
|
|
18452
18786
|
function useObjectBindingIds(objectBindings) {
|
|
18453
|
-
return (0,
|
|
18787
|
+
return (0, import_react46.useMemo)(
|
|
18454
18788
|
() => Object.values(objectBindings).map((binding) => binding.modelObjectId),
|
|
18455
18789
|
[objectBindings]
|
|
18456
18790
|
);
|
|
18457
18791
|
}
|
|
18458
18792
|
|
|
18459
18793
|
// src/hooks/useObjectBindings.ts
|
|
18460
|
-
var
|
|
18794
|
+
var import_react47 = require("react");
|
|
18461
18795
|
|
|
18462
18796
|
// src/utils/deepMerge.ts
|
|
18463
18797
|
function isPlainObject2(value) {
|
|
@@ -18475,6 +18809,27 @@ function deepMerge(base, patch) {
|
|
|
18475
18809
|
return target;
|
|
18476
18810
|
}
|
|
18477
18811
|
|
|
18812
|
+
// src/utils/selectBindings.ts
|
|
18813
|
+
function isSelector(target) {
|
|
18814
|
+
return typeof target === "object" && !Array.isArray(target);
|
|
18815
|
+
}
|
|
18816
|
+
function matchesSelector(binding, selector) {
|
|
18817
|
+
if ("group" in selector) return binding.group === selector.group;
|
|
18818
|
+
if ("tag" in selector) return binding.tags?.includes(selector.tag) ?? false;
|
|
18819
|
+
return binding.type === selector.type;
|
|
18820
|
+
}
|
|
18821
|
+
function selectBindingKeys(bindings, target) {
|
|
18822
|
+
if (isSelector(target)) {
|
|
18823
|
+
return Object.entries(bindings).filter(([, binding]) => matchesSelector(binding, target)).map(([bindingKey]) => bindingKey);
|
|
18824
|
+
}
|
|
18825
|
+
const ids = typeof target === "string" ? [target] : target;
|
|
18826
|
+
const keys = ids.map((id) => resolveBindingKey(bindings, id)).filter((key) => key !== null);
|
|
18827
|
+
return [...new Set(keys)];
|
|
18828
|
+
}
|
|
18829
|
+
function selectBindings(bindings, target) {
|
|
18830
|
+
return selectBindingKeys(bindings, target).map((key) => bindings[key]).filter((binding) => binding !== void 0);
|
|
18831
|
+
}
|
|
18832
|
+
|
|
18478
18833
|
// src/utils/patchBindings.ts
|
|
18479
18834
|
function isBindingEditArray(value) {
|
|
18480
18835
|
return Array.isArray(value) && value.length > 0 && typeof value[0] !== "string";
|
|
@@ -18483,10 +18838,7 @@ function patchBindings(bindings, objectIdOrEdits, patch) {
|
|
|
18483
18838
|
const edits = isBindingEditArray(objectIdOrEdits) ? objectIdOrEdits : [{ ids: objectIdOrEdits, patch: patch ?? {} }];
|
|
18484
18839
|
let next = bindings;
|
|
18485
18840
|
for (const edit of edits) {
|
|
18486
|
-
const
|
|
18487
|
-
for (const id of ids) {
|
|
18488
|
-
const bindingKey = resolveBindingKey(next, id);
|
|
18489
|
-
if (!bindingKey) continue;
|
|
18841
|
+
for (const bindingKey of selectBindingKeys(next, edit.ids)) {
|
|
18490
18842
|
const binding = next[bindingKey];
|
|
18491
18843
|
if (!binding) continue;
|
|
18492
18844
|
const patchedBinding = deepMerge(binding, edit.patch);
|
|
@@ -18501,14 +18853,44 @@ function material(value) {
|
|
|
18501
18853
|
}
|
|
18502
18854
|
|
|
18503
18855
|
// src/hooks/useObjectBindings.ts
|
|
18856
|
+
var TEXTURE_PROPERTY_BY_CHANNEL = {
|
|
18857
|
+
baseColor: "texture",
|
|
18858
|
+
metalness: "metalnessMap",
|
|
18859
|
+
roughness: "roughnessMap",
|
|
18860
|
+
emissive: "emissiveMap",
|
|
18861
|
+
alpha: "alphaMap",
|
|
18862
|
+
normal: "normalMap",
|
|
18863
|
+
bump: "bumpMap",
|
|
18864
|
+
ao: "aoMap",
|
|
18865
|
+
displacement: "displacementMap",
|
|
18866
|
+
clearcoat: "clearcoatMap",
|
|
18867
|
+
clearcoatRoughness: "clearcoatRoughnessMap",
|
|
18868
|
+
clearcoatNormal: "clearcoatNormalMap",
|
|
18869
|
+
anisotropy: "anisotropyMap",
|
|
18870
|
+
transmission: "transmissionMap",
|
|
18871
|
+
thickness: "thicknessMap",
|
|
18872
|
+
sheenColor: "sheenColorMap",
|
|
18873
|
+
sheenRoughness: "sheenRoughnessMap",
|
|
18874
|
+
specularIntensity: "specularIntensityMap",
|
|
18875
|
+
specularColor: "specularColorMap"
|
|
18876
|
+
};
|
|
18877
|
+
function cloneMaterial(value) {
|
|
18878
|
+
if (!value) return void 0;
|
|
18879
|
+
return Object.fromEntries(
|
|
18880
|
+
Object.entries(value).map(([key, field]) => [
|
|
18881
|
+
key,
|
|
18882
|
+
field && typeof field === "object" ? { ...field } : field
|
|
18883
|
+
])
|
|
18884
|
+
);
|
|
18885
|
+
}
|
|
18504
18886
|
function getHiddenObjects(objectBindings) {
|
|
18505
18887
|
return Object.fromEntries(
|
|
18506
18888
|
Object.entries(objectBindings).filter(([, binding]) => binding.visible === false).map(([bindingKey]) => [bindingKey, true])
|
|
18507
18889
|
);
|
|
18508
18890
|
}
|
|
18509
18891
|
function useObjectBindings(initialBindings) {
|
|
18510
|
-
const [objectBindings, setObjectBindings] = (0,
|
|
18511
|
-
const updateObjectBindings = (0,
|
|
18892
|
+
const [objectBindings, setObjectBindings] = (0, import_react47.useState)(initialBindings);
|
|
18893
|
+
const updateObjectBindings = (0, import_react47.useCallback)(
|
|
18512
18894
|
(objectIdOrEdits, patchValue) => {
|
|
18513
18895
|
setObjectBindings(
|
|
18514
18896
|
(current) => patchValue === void 0 ? patchBindings(current, objectIdOrEdits) : patchBindings(
|
|
@@ -18520,68 +18902,138 @@ function useObjectBindings(initialBindings) {
|
|
|
18520
18902
|
},
|
|
18521
18903
|
[]
|
|
18522
18904
|
);
|
|
18523
|
-
const setMaterial = (0,
|
|
18524
|
-
(
|
|
18905
|
+
const setMaterial = (0, import_react47.useCallback)(
|
|
18906
|
+
(target, value) => updateObjectBindings(target, material(value)),
|
|
18525
18907
|
[updateObjectBindings]
|
|
18526
18908
|
);
|
|
18527
|
-
const setBaseColor = (0,
|
|
18528
|
-
(
|
|
18909
|
+
const setBaseColor = (0, import_react47.useCallback)(
|
|
18910
|
+
(target, color) => setMaterial(target, { baseColor: color }),
|
|
18529
18911
|
[setMaterial]
|
|
18530
18912
|
);
|
|
18531
|
-
const
|
|
18532
|
-
(
|
|
18913
|
+
const setTexture = (0, import_react47.useCallback)(
|
|
18914
|
+
(target, texture, channel = "baseColor") => {
|
|
18915
|
+
const property = TEXTURE_PROPERTY_BY_CHANNEL[channel];
|
|
18916
|
+
const slot = typeof texture === "string" ? { path: texture } : texture;
|
|
18917
|
+
updateObjectBindings(target, {
|
|
18918
|
+
style: { material: { [property]: slot } }
|
|
18919
|
+
});
|
|
18920
|
+
},
|
|
18533
18921
|
[updateObjectBindings]
|
|
18534
18922
|
);
|
|
18535
|
-
const
|
|
18536
|
-
(
|
|
18537
|
-
const
|
|
18538
|
-
|
|
18923
|
+
const clearTexture = (0, import_react47.useCallback)(
|
|
18924
|
+
(target, channel = "baseColor") => {
|
|
18925
|
+
const property = TEXTURE_PROPERTY_BY_CHANNEL[channel];
|
|
18926
|
+
updateObjectBindings(target, {
|
|
18927
|
+
style: { material: { [property]: void 0 } }
|
|
18928
|
+
});
|
|
18539
18929
|
},
|
|
18540
|
-
[objectBindings]
|
|
18541
|
-
);
|
|
18542
|
-
const hideObject = (0, import_react46.useCallback)(
|
|
18543
|
-
(objectId) => updateObjectBindings(objectId, { visible: false }),
|
|
18544
18930
|
[updateObjectBindings]
|
|
18545
18931
|
);
|
|
18546
|
-
const
|
|
18547
|
-
(
|
|
18932
|
+
const copyMaterial = (0, import_react47.useCallback)(
|
|
18933
|
+
(source, target) => {
|
|
18934
|
+
setObjectBindings((current) => {
|
|
18935
|
+
const sourceKey = resolveBindingKey(current, source);
|
|
18936
|
+
if (!sourceKey) return current;
|
|
18937
|
+
const sourceMaterial = cloneMaterial(
|
|
18938
|
+
current[sourceKey]?.style?.material
|
|
18939
|
+
);
|
|
18940
|
+
const targetKeys = selectBindingKeys(current, target);
|
|
18941
|
+
if (targetKeys.length === 0) return current;
|
|
18942
|
+
let next = current;
|
|
18943
|
+
for (const targetKey of targetKeys) {
|
|
18944
|
+
const binding = current[targetKey];
|
|
18945
|
+
if (!binding) continue;
|
|
18946
|
+
if (next === current) next = { ...current };
|
|
18947
|
+
next[targetKey] = {
|
|
18948
|
+
...binding,
|
|
18949
|
+
style: {
|
|
18950
|
+
...binding.style,
|
|
18951
|
+
material: cloneMaterial(sourceMaterial)
|
|
18952
|
+
}
|
|
18953
|
+
};
|
|
18954
|
+
}
|
|
18955
|
+
return next;
|
|
18956
|
+
});
|
|
18957
|
+
},
|
|
18958
|
+
[]
|
|
18959
|
+
);
|
|
18960
|
+
const resetMaterial = (0, import_react47.useCallback)(
|
|
18961
|
+
(target) => updateObjectBindings(target, { style: { material: void 0 } }),
|
|
18962
|
+
[updateObjectBindings]
|
|
18963
|
+
);
|
|
18964
|
+
const setTransform = (0, import_react47.useCallback)(
|
|
18965
|
+
(target, transform) => updateObjectBindings(target, { transform }),
|
|
18966
|
+
[updateObjectBindings]
|
|
18967
|
+
);
|
|
18968
|
+
const resetTransform = (0, import_react47.useCallback)(
|
|
18969
|
+
(target) => updateObjectBindings(target, { transform: void 0 }),
|
|
18548
18970
|
[updateObjectBindings]
|
|
18549
18971
|
);
|
|
18550
|
-
const
|
|
18972
|
+
const updateMetadata = (0, import_react47.useCallback)(
|
|
18973
|
+
(target, metadata) => updateObjectBindings(target, { metadata }),
|
|
18974
|
+
[updateObjectBindings]
|
|
18975
|
+
);
|
|
18976
|
+
const selectObjectBindings = (0, import_react47.useCallback)(
|
|
18977
|
+
(target) => selectBindings(objectBindings, target),
|
|
18978
|
+
[objectBindings]
|
|
18979
|
+
);
|
|
18980
|
+
const selectObjectBindingIds = (0, import_react47.useCallback)(
|
|
18981
|
+
(target) => selectBindingKeys(objectBindings, target).map(
|
|
18982
|
+
(bindingKey) => objectBindings[bindingKey]?.id ?? bindingKey
|
|
18983
|
+
),
|
|
18984
|
+
[objectBindings]
|
|
18985
|
+
);
|
|
18986
|
+
const getMaterial = (0, import_react47.useCallback)(
|
|
18551
18987
|
(objectId) => {
|
|
18988
|
+
const bindingKey = resolveBindingKey(objectBindings, objectId);
|
|
18989
|
+
return bindingKey ? objectBindings[bindingKey]?.style?.material ?? null : null;
|
|
18990
|
+
},
|
|
18991
|
+
[objectBindings]
|
|
18992
|
+
);
|
|
18993
|
+
const hideObject = (0, import_react47.useCallback)(
|
|
18994
|
+
(target) => updateObjectBindings(target, { visible: false }),
|
|
18995
|
+
[updateObjectBindings]
|
|
18996
|
+
);
|
|
18997
|
+
const showObject = (0, import_react47.useCallback)(
|
|
18998
|
+
(target) => updateObjectBindings(target, { visible: true }),
|
|
18999
|
+
[updateObjectBindings]
|
|
19000
|
+
);
|
|
19001
|
+
const toggleObjectVisibility = (0, import_react47.useCallback)(
|
|
19002
|
+
(target) => {
|
|
18552
19003
|
setObjectBindings((current) => {
|
|
18553
|
-
const
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
|
|
18557
|
-
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
|
|
18561
|
-
|
|
18562
|
-
|
|
18563
|
-
|
|
19004
|
+
const edits = selectBindingKeys(current, target).reduce(
|
|
19005
|
+
(acc, bindingKey) => {
|
|
19006
|
+
const binding = current[bindingKey];
|
|
19007
|
+
if (!binding) return acc;
|
|
19008
|
+
acc.push({
|
|
19009
|
+
ids: bindingKey,
|
|
19010
|
+
patch: { visible: binding.visible === false }
|
|
19011
|
+
});
|
|
19012
|
+
return acc;
|
|
19013
|
+
},
|
|
19014
|
+
[]
|
|
19015
|
+
);
|
|
18564
19016
|
return patchBindings(current, edits);
|
|
18565
19017
|
});
|
|
18566
19018
|
},
|
|
18567
19019
|
[setObjectBindings]
|
|
18568
19020
|
);
|
|
18569
|
-
const clearHiddenObjects = (0,
|
|
19021
|
+
const clearHiddenObjects = (0, import_react47.useCallback)(() => {
|
|
18570
19022
|
setObjectBindings(
|
|
18571
19023
|
(current) => patchBindings(current, Object.keys(current), { visible: true })
|
|
18572
19024
|
);
|
|
18573
19025
|
}, [setObjectBindings]);
|
|
18574
|
-
const hiddenObjects = (0,
|
|
19026
|
+
const hiddenObjects = (0, import_react47.useMemo)(
|
|
18575
19027
|
() => getHiddenObjects(objectBindings),
|
|
18576
19028
|
[objectBindings]
|
|
18577
19029
|
);
|
|
18578
|
-
const hiddenObjectIds = (0,
|
|
19030
|
+
const hiddenObjectIds = (0, import_react47.useMemo)(
|
|
18579
19031
|
() => Object.keys(hiddenObjects).map(
|
|
18580
19032
|
(bindingKey) => objectBindings[bindingKey]?.id ?? bindingKey
|
|
18581
19033
|
),
|
|
18582
19034
|
[hiddenObjects, objectBindings]
|
|
18583
19035
|
);
|
|
18584
|
-
const isObjectHidden = (0,
|
|
19036
|
+
const isObjectHidden = (0, import_react47.useCallback)(
|
|
18585
19037
|
(objectId) => {
|
|
18586
19038
|
const bindingKey = resolveBindingKey(objectBindings, objectId);
|
|
18587
19039
|
return bindingKey ? objectBindings[bindingKey]?.visible === false : false;
|
|
@@ -18594,8 +19046,16 @@ function useObjectBindings(initialBindings) {
|
|
|
18594
19046
|
updateObjectBindings,
|
|
18595
19047
|
setMaterial,
|
|
18596
19048
|
setBaseColor,
|
|
19049
|
+
setTexture,
|
|
19050
|
+
clearTexture,
|
|
19051
|
+
copyMaterial,
|
|
18597
19052
|
resetMaterial,
|
|
18598
19053
|
getMaterial,
|
|
19054
|
+
setTransform,
|
|
19055
|
+
resetTransform,
|
|
19056
|
+
updateMetadata,
|
|
19057
|
+
selectObjectBindings,
|
|
19058
|
+
selectObjectBindingIds,
|
|
18599
19059
|
hiddenObjects,
|
|
18600
19060
|
hiddenObjectIds,
|
|
18601
19061
|
hideObject,
|
|
@@ -18606,8 +19066,13 @@ function useObjectBindings(initialBindings) {
|
|
|
18606
19066
|
};
|
|
18607
19067
|
}
|
|
18608
19068
|
|
|
19069
|
+
// src/utils/defineObjectBindings.ts
|
|
19070
|
+
function defineObjectBindings(bindings) {
|
|
19071
|
+
return bindings;
|
|
19072
|
+
}
|
|
19073
|
+
|
|
18609
19074
|
// src/hooks/useSceneConfig.ts
|
|
18610
|
-
var
|
|
19075
|
+
var import_react48 = require("react");
|
|
18611
19076
|
|
|
18612
19077
|
// src/utils/patchSceneConfig.ts
|
|
18613
19078
|
function patchSceneConfig(sceneConfig, patch) {
|
|
@@ -18615,36 +19080,154 @@ function patchSceneConfig(sceneConfig, patch) {
|
|
|
18615
19080
|
}
|
|
18616
19081
|
|
|
18617
19082
|
// src/hooks/useSceneConfig.ts
|
|
19083
|
+
var DEFAULT_LIGHT = {
|
|
19084
|
+
type: "point",
|
|
19085
|
+
color: "#ffffff",
|
|
19086
|
+
intensity: 1,
|
|
19087
|
+
position: [0, 0, 0],
|
|
19088
|
+
distance: 0,
|
|
19089
|
+
decay: 2,
|
|
19090
|
+
attachedToCamera: false,
|
|
19091
|
+
castShadow: false,
|
|
19092
|
+
shadowBias: -5e-4,
|
|
19093
|
+
visible: true
|
|
19094
|
+
};
|
|
18618
19095
|
function useSceneConfig(initialSceneConfig) {
|
|
18619
|
-
const initialSceneConfigRef = (0,
|
|
18620
|
-
const [sceneConfig, setSceneConfig] = (0,
|
|
19096
|
+
const initialSceneConfigRef = (0, import_react48.useRef)(null);
|
|
19097
|
+
const [sceneConfig, setSceneConfig] = (0, import_react48.useState)(() => {
|
|
18621
19098
|
const initial = typeof initialSceneConfig === "function" ? initialSceneConfig() : initialSceneConfig;
|
|
18622
19099
|
initialSceneConfigRef.current = initial;
|
|
18623
19100
|
return initial;
|
|
18624
19101
|
});
|
|
18625
|
-
const updateSceneConfig = (0,
|
|
19102
|
+
const updateSceneConfig = (0, import_react48.useCallback)((update) => {
|
|
18626
19103
|
setSceneConfig((current) => {
|
|
18627
19104
|
const patch = typeof update === "function" ? update(current) : update;
|
|
18628
19105
|
return patchSceneConfig(current, patch);
|
|
18629
19106
|
});
|
|
18630
19107
|
}, []);
|
|
18631
|
-
const resetSceneConfig = (0,
|
|
19108
|
+
const resetSceneConfig = (0, import_react48.useCallback)(() => {
|
|
18632
19109
|
const initial = initialSceneConfigRef.current;
|
|
18633
19110
|
if (initial) setSceneConfig(initial);
|
|
18634
19111
|
}, []);
|
|
19112
|
+
const updateLight = (0, import_react48.useCallback)(
|
|
19113
|
+
(id, patch) => {
|
|
19114
|
+
updateSceneConfig((current) => ({
|
|
19115
|
+
lighting: {
|
|
19116
|
+
lights: current.lighting.lights.map(
|
|
19117
|
+
(light) => light.id === id ? { ...light, ...patch } : light
|
|
19118
|
+
)
|
|
19119
|
+
}
|
|
19120
|
+
}));
|
|
19121
|
+
},
|
|
19122
|
+
[updateSceneConfig]
|
|
19123
|
+
);
|
|
19124
|
+
const addLight = (0, import_react48.useCallback)(
|
|
19125
|
+
(light) => {
|
|
19126
|
+
updateSceneConfig((current) => {
|
|
19127
|
+
if (current.lighting.lights.some((item) => item.id === light.id)) {
|
|
19128
|
+
return {};
|
|
19129
|
+
}
|
|
19130
|
+
return {
|
|
19131
|
+
lighting: {
|
|
19132
|
+
lights: [
|
|
19133
|
+
...current.lighting.lights,
|
|
19134
|
+
{ ...DEFAULT_LIGHT, ...light }
|
|
19135
|
+
]
|
|
19136
|
+
}
|
|
19137
|
+
};
|
|
19138
|
+
});
|
|
19139
|
+
},
|
|
19140
|
+
[updateSceneConfig]
|
|
19141
|
+
);
|
|
19142
|
+
const removeLight = (0, import_react48.useCallback)(
|
|
19143
|
+
(id) => {
|
|
19144
|
+
updateSceneConfig((current) => ({
|
|
19145
|
+
lighting: {
|
|
19146
|
+
lights: current.lighting.lights.filter((light) => light.id !== id)
|
|
19147
|
+
}
|
|
19148
|
+
}));
|
|
19149
|
+
},
|
|
19150
|
+
[updateSceneConfig]
|
|
19151
|
+
);
|
|
19152
|
+
const setLightIntensity = (0, import_react48.useCallback)(
|
|
19153
|
+
(id, intensity) => updateLight(id, { intensity }),
|
|
19154
|
+
[updateLight]
|
|
19155
|
+
);
|
|
19156
|
+
const setLightColor = (0, import_react48.useCallback)(
|
|
19157
|
+
(id, color) => updateLight(id, { color }),
|
|
19158
|
+
[updateLight]
|
|
19159
|
+
);
|
|
19160
|
+
const showLight = (0, import_react48.useCallback)(
|
|
19161
|
+
(id) => updateLight(id, { visible: true }),
|
|
19162
|
+
[updateLight]
|
|
19163
|
+
);
|
|
19164
|
+
const hideLight = (0, import_react48.useCallback)(
|
|
19165
|
+
(id) => updateLight(id, { visible: false }),
|
|
19166
|
+
[updateLight]
|
|
19167
|
+
);
|
|
19168
|
+
const toggleLight = (0, import_react48.useCallback)(
|
|
19169
|
+
(id) => {
|
|
19170
|
+
updateSceneConfig((current) => ({
|
|
19171
|
+
lighting: {
|
|
19172
|
+
lights: current.lighting.lights.map(
|
|
19173
|
+
(light) => light.id === id ? { ...light, visible: !light.visible } : light
|
|
19174
|
+
)
|
|
19175
|
+
}
|
|
19176
|
+
}));
|
|
19177
|
+
},
|
|
19178
|
+
[updateSceneConfig]
|
|
19179
|
+
);
|
|
19180
|
+
const attachLight = (0, import_react48.useCallback)(
|
|
19181
|
+
(id, attachment) => updateLight(id, { attachment, attachedToCamera: false }),
|
|
19182
|
+
[updateLight]
|
|
19183
|
+
);
|
|
19184
|
+
const detachLight = (0, import_react48.useCallback)(
|
|
19185
|
+
(id) => updateLight(id, { attachment: void 0 }),
|
|
19186
|
+
[updateLight]
|
|
19187
|
+
);
|
|
19188
|
+
const lights = (0, import_react48.useMemo)(
|
|
19189
|
+
() => ({
|
|
19190
|
+
items: sceneConfig.lighting.lights,
|
|
19191
|
+
get: (id) => sceneConfig.lighting.lights.find((light) => light.id === id),
|
|
19192
|
+
add: addLight,
|
|
19193
|
+
update: updateLight,
|
|
19194
|
+
remove: removeLight,
|
|
19195
|
+
setIntensity: setLightIntensity,
|
|
19196
|
+
setColor: setLightColor,
|
|
19197
|
+
show: showLight,
|
|
19198
|
+
hide: hideLight,
|
|
19199
|
+
toggle: toggleLight,
|
|
19200
|
+
attach: attachLight,
|
|
19201
|
+
detach: detachLight
|
|
19202
|
+
}),
|
|
19203
|
+
[
|
|
19204
|
+
sceneConfig.lighting.lights,
|
|
19205
|
+
addLight,
|
|
19206
|
+
updateLight,
|
|
19207
|
+
removeLight,
|
|
19208
|
+
setLightIntensity,
|
|
19209
|
+
setLightColor,
|
|
19210
|
+
showLight,
|
|
19211
|
+
hideLight,
|
|
19212
|
+
toggleLight,
|
|
19213
|
+
attachLight,
|
|
19214
|
+
detachLight
|
|
19215
|
+
]
|
|
19216
|
+
);
|
|
18635
19217
|
return {
|
|
18636
19218
|
sceneConfig,
|
|
18637
19219
|
setSceneConfig,
|
|
18638
19220
|
updateSceneConfig,
|
|
18639
|
-
resetSceneConfig
|
|
19221
|
+
resetSceneConfig,
|
|
19222
|
+
lights
|
|
18640
19223
|
};
|
|
18641
19224
|
}
|
|
18642
19225
|
|
|
18643
19226
|
// src/hooks/useViewerHover.ts
|
|
18644
|
-
var
|
|
19227
|
+
var import_react49 = require("react");
|
|
18645
19228
|
function useViewerHover() {
|
|
18646
|
-
const [hoveredObjectBinding, setHoveredObjectBinding] = (0,
|
|
18647
|
-
const handleHoveredObject = (0,
|
|
19229
|
+
const [hoveredObjectBinding, setHoveredObjectBinding] = (0, import_react49.useState)(null);
|
|
19230
|
+
const handleHoveredObject = (0, import_react49.useCallback)(
|
|
18648
19231
|
(binding) => {
|
|
18649
19232
|
setHoveredObjectBinding(binding);
|
|
18650
19233
|
},
|
|
@@ -18657,23 +19240,23 @@ function useViewerHover() {
|
|
|
18657
19240
|
}
|
|
18658
19241
|
|
|
18659
19242
|
// src/hooks/useViewerModel.ts
|
|
18660
|
-
var
|
|
18661
|
-
var
|
|
19243
|
+
var import_react50 = require("react");
|
|
19244
|
+
var import_three24 = require("three");
|
|
18662
19245
|
function toTuple2(vector) {
|
|
18663
19246
|
return [vector.x, vector.y, vector.z];
|
|
18664
19247
|
}
|
|
18665
19248
|
function useViewerModel() {
|
|
18666
|
-
const [isLoading, setIsLoading] = (0,
|
|
18667
|
-
const [isReady, setIsReady] = (0,
|
|
18668
|
-
const [error, setError] = (0,
|
|
18669
|
-
const [bounds, setBounds] = (0,
|
|
18670
|
-
const [objectCount, setObjectCount] = (0,
|
|
18671
|
-
const handleModelLoaded = (0,
|
|
18672
|
-
const box = new
|
|
19249
|
+
const [isLoading, setIsLoading] = (0, import_react50.useState)(true);
|
|
19250
|
+
const [isReady, setIsReady] = (0, import_react50.useState)(false);
|
|
19251
|
+
const [error, setError] = (0, import_react50.useState)(null);
|
|
19252
|
+
const [bounds, setBounds] = (0, import_react50.useState)(null);
|
|
19253
|
+
const [objectCount, setObjectCount] = (0, import_react50.useState)(0);
|
|
19254
|
+
const handleModelLoaded = (0, import_react50.useCallback)((scene) => {
|
|
19255
|
+
const box = new import_three24.Box3().setFromObject(scene);
|
|
18673
19256
|
const min = box.min.clone();
|
|
18674
19257
|
const max = box.max.clone();
|
|
18675
|
-
const center = new
|
|
18676
|
-
const size = new
|
|
19258
|
+
const center = new import_three24.Vector3();
|
|
19259
|
+
const size = new import_three24.Vector3();
|
|
18677
19260
|
let nextObjectCount = 0;
|
|
18678
19261
|
scene.traverse((child) => {
|
|
18679
19262
|
if ("isMesh" in child && child.isMesh) {
|
|
@@ -18693,14 +19276,14 @@ function useViewerModel() {
|
|
|
18693
19276
|
setIsLoading(false);
|
|
18694
19277
|
setIsReady(true);
|
|
18695
19278
|
}, []);
|
|
18696
|
-
const handleLoadError = (0,
|
|
19279
|
+
const handleLoadError = (0, import_react50.useCallback)((nextError) => {
|
|
18697
19280
|
setError(nextError);
|
|
18698
19281
|
setBounds(null);
|
|
18699
19282
|
setObjectCount(0);
|
|
18700
19283
|
setIsLoading(false);
|
|
18701
19284
|
setIsReady(false);
|
|
18702
19285
|
}, []);
|
|
18703
|
-
const resetModelState = (0,
|
|
19286
|
+
const resetModelState = (0, import_react50.useCallback)(() => {
|
|
18704
19287
|
setIsLoading(true);
|
|
18705
19288
|
setIsReady(false);
|
|
18706
19289
|
setError(null);
|
|
@@ -18720,62 +19303,774 @@ function useViewerModel() {
|
|
|
18720
19303
|
}
|
|
18721
19304
|
|
|
18722
19305
|
// src/hooks/useViewerActions.ts
|
|
18723
|
-
var
|
|
18724
|
-
function useViewerActions(
|
|
18725
|
-
|
|
18726
|
-
|
|
19306
|
+
var import_react51 = require("react");
|
|
19307
|
+
function useViewerActions({
|
|
19308
|
+
bindings,
|
|
19309
|
+
scene,
|
|
19310
|
+
camera,
|
|
19311
|
+
animations,
|
|
19312
|
+
onAction
|
|
19313
|
+
}) {
|
|
19314
|
+
const {
|
|
19315
|
+
objectBindings,
|
|
19316
|
+
updateObjectBindings,
|
|
19317
|
+
showObject,
|
|
19318
|
+
hideObject,
|
|
19319
|
+
toggleObjectVisibility
|
|
19320
|
+
} = bindings;
|
|
19321
|
+
const updateSceneConfig = scene?.updateSceneConfig;
|
|
19322
|
+
const focusObject = camera?.focusObject;
|
|
19323
|
+
const fitScene = camera?.fitScene;
|
|
19324
|
+
const resetView = camera?.resetView;
|
|
19325
|
+
const setCameraTarget = camera?.setCameraTarget;
|
|
19326
|
+
const setCameraState = camera?.setCameraState;
|
|
19327
|
+
const playAnimation = animations?.play;
|
|
19328
|
+
const pauseAnimation = animations?.pause;
|
|
19329
|
+
const stopAnimation = animations?.stop;
|
|
19330
|
+
const setAnimationSpeed = animations?.setSpeed;
|
|
19331
|
+
const seekAnimation = animations?.seek;
|
|
19332
|
+
const getActionsForObject = (0, import_react51.useCallback)(
|
|
18727
19333
|
(objectId) => {
|
|
18728
19334
|
const bindingKey = resolveBindingKey(objectBindings, objectId);
|
|
18729
|
-
|
|
18730
|
-
return [];
|
|
18731
|
-
}
|
|
18732
|
-
return objectBindings[bindingKey]?.actions ?? [];
|
|
19335
|
+
return bindingKey ? objectBindings[bindingKey]?.actions ?? [] : [];
|
|
18733
19336
|
},
|
|
18734
19337
|
[objectBindings]
|
|
18735
19338
|
);
|
|
18736
|
-
const
|
|
18737
|
-
(
|
|
18738
|
-
const
|
|
18739
|
-
|
|
18740
|
-
|
|
19339
|
+
const handleAction = (0, import_react51.useCallback)(
|
|
19340
|
+
async (event) => {
|
|
19341
|
+
for (const effect of event.action.effects ?? []) {
|
|
19342
|
+
if ("objectBindings" in effect) {
|
|
19343
|
+
updateObjectBindings(effect.target, effect.objectBindings);
|
|
19344
|
+
continue;
|
|
19345
|
+
}
|
|
19346
|
+
if ("sceneConfig" in effect) {
|
|
19347
|
+
updateSceneConfig?.(effect.sceneConfig);
|
|
19348
|
+
continue;
|
|
19349
|
+
}
|
|
19350
|
+
if ("visibility" in effect) {
|
|
19351
|
+
if (effect.visibility === "show") showObject(effect.target);
|
|
19352
|
+
else if (effect.visibility === "hide") hideObject(effect.target);
|
|
19353
|
+
else toggleObjectVisibility(effect.target);
|
|
19354
|
+
continue;
|
|
19355
|
+
}
|
|
19356
|
+
if ("camera" in effect) {
|
|
19357
|
+
const action2 = effect.camera;
|
|
19358
|
+
if (action2.type === "focus-object") {
|
|
19359
|
+
await focusObject?.(action2.objectId ?? event.objectId);
|
|
19360
|
+
} else if (action2.type === "fit-scene") {
|
|
19361
|
+
await fitScene?.();
|
|
19362
|
+
} else if (action2.type === "reset") {
|
|
19363
|
+
await resetView?.();
|
|
19364
|
+
} else if (action2.type === "set-target") {
|
|
19365
|
+
await setCameraTarget?.(action2.target, action2.transition ?? true);
|
|
19366
|
+
} else {
|
|
19367
|
+
await setCameraState?.(action2.state, action2.transition ?? true);
|
|
19368
|
+
}
|
|
19369
|
+
continue;
|
|
19370
|
+
}
|
|
19371
|
+
const action = effect.animation;
|
|
19372
|
+
if (action.type === "play") playAnimation?.(action.clip);
|
|
19373
|
+
else if (action.type === "pause") pauseAnimation?.();
|
|
19374
|
+
else if (action.type === "stop") stopAnimation?.();
|
|
19375
|
+
else if (action.type === "set-speed") {
|
|
19376
|
+
setAnimationSpeed?.(action.speed);
|
|
19377
|
+
} else {
|
|
19378
|
+
seekAnimation?.(action.time);
|
|
19379
|
+
}
|
|
18741
19380
|
}
|
|
19381
|
+
await onAction?.(event);
|
|
19382
|
+
},
|
|
19383
|
+
[
|
|
19384
|
+
fitScene,
|
|
19385
|
+
focusObject,
|
|
19386
|
+
hideObject,
|
|
19387
|
+
onAction,
|
|
19388
|
+
pauseAnimation,
|
|
19389
|
+
playAnimation,
|
|
19390
|
+
resetView,
|
|
19391
|
+
seekAnimation,
|
|
19392
|
+
setAnimationSpeed,
|
|
19393
|
+
setCameraState,
|
|
19394
|
+
setCameraTarget,
|
|
19395
|
+
showObject,
|
|
19396
|
+
stopAnimation,
|
|
19397
|
+
toggleObjectVisibility,
|
|
19398
|
+
updateObjectBindings,
|
|
19399
|
+
updateSceneConfig
|
|
19400
|
+
]
|
|
19401
|
+
);
|
|
19402
|
+
const runAction = (0, import_react51.useCallback)(
|
|
19403
|
+
async (objectId, actionId) => {
|
|
19404
|
+
const bindingKey = resolveBindingKey(objectBindings, objectId);
|
|
19405
|
+
if (!bindingKey) return null;
|
|
18742
19406
|
const binding = objectBindings[bindingKey];
|
|
18743
|
-
|
|
18744
|
-
|
|
18745
|
-
}
|
|
18746
|
-
const action = (binding.actions ?? []).find(
|
|
18747
|
-
(entry) => entry.id === actionId
|
|
18748
|
-
);
|
|
18749
|
-
if (!action) {
|
|
18750
|
-
return null;
|
|
18751
|
-
}
|
|
19407
|
+
const action = binding?.actions?.find((entry) => entry.id === actionId);
|
|
19408
|
+
if (!binding || !action) return null;
|
|
18752
19409
|
const event = {
|
|
18753
19410
|
objectId: bindingKey,
|
|
18754
19411
|
action,
|
|
18755
19412
|
binding
|
|
18756
19413
|
};
|
|
18757
|
-
|
|
18758
|
-
onObjectBindingsChange({
|
|
18759
|
-
...objectBindings,
|
|
18760
|
-
[bindingKey]: {
|
|
18761
|
-
...binding,
|
|
18762
|
-
visible: binding.visible === false
|
|
18763
|
-
}
|
|
18764
|
-
});
|
|
18765
|
-
}
|
|
18766
|
-
onAction?.(event);
|
|
19414
|
+
await handleAction(event);
|
|
18767
19415
|
return event;
|
|
18768
19416
|
},
|
|
18769
|
-
[
|
|
19417
|
+
[handleAction, objectBindings]
|
|
18770
19418
|
);
|
|
18771
19419
|
return {
|
|
18772
19420
|
getActionsForObject,
|
|
19421
|
+
handleAction,
|
|
18773
19422
|
runAction
|
|
18774
19423
|
};
|
|
18775
19424
|
}
|
|
18776
19425
|
|
|
19426
|
+
// src/hooks/useViewerConnection.ts
|
|
19427
|
+
var import_react52 = require("react");
|
|
19428
|
+
function getReadyHandler(consumer) {
|
|
19429
|
+
if (typeof consumer === "function") {
|
|
19430
|
+
return consumer;
|
|
19431
|
+
}
|
|
19432
|
+
return consumer?.handleViewerReady ?? null;
|
|
19433
|
+
}
|
|
19434
|
+
function useViewerConnection(...consumers) {
|
|
19435
|
+
const viewerRef = (0, import_react52.useRef)(null);
|
|
19436
|
+
const consumersRef = (0, import_react52.useRef)(consumers);
|
|
19437
|
+
consumersRef.current = consumers;
|
|
19438
|
+
const handleViewerReady = (0, import_react52.useCallback)((viewer) => {
|
|
19439
|
+
viewerRef.current = viewer;
|
|
19440
|
+
const invoked = /* @__PURE__ */ new Set();
|
|
19441
|
+
for (const consumer of consumersRef.current) {
|
|
19442
|
+
const handler = getReadyHandler(consumer);
|
|
19443
|
+
if (handler && !invoked.has(handler)) {
|
|
19444
|
+
invoked.add(handler);
|
|
19445
|
+
handler(viewer);
|
|
19446
|
+
}
|
|
19447
|
+
}
|
|
19448
|
+
}, []);
|
|
19449
|
+
const getViewer = (0, import_react52.useCallback)(() => viewerRef.current, []);
|
|
19450
|
+
const captureImage2 = (0, import_react52.useCallback)((options) => {
|
|
19451
|
+
const viewer = viewerRef.current;
|
|
19452
|
+
if (!viewer) {
|
|
19453
|
+
return Promise.reject(new Error("ModelViewer is not ready yet."));
|
|
19454
|
+
}
|
|
19455
|
+
return viewer.captureImage(options);
|
|
19456
|
+
}, []);
|
|
19457
|
+
const invalidate = (0, import_react52.useCallback)(() => {
|
|
19458
|
+
const viewer = viewerRef.current;
|
|
19459
|
+
if (!viewer) {
|
|
19460
|
+
return false;
|
|
19461
|
+
}
|
|
19462
|
+
viewer.invalidate();
|
|
19463
|
+
return true;
|
|
19464
|
+
}, []);
|
|
19465
|
+
return {
|
|
19466
|
+
handleViewerReady,
|
|
19467
|
+
getViewer,
|
|
19468
|
+
captureImage: captureImage2,
|
|
19469
|
+
invalidate
|
|
19470
|
+
};
|
|
19471
|
+
}
|
|
19472
|
+
|
|
19473
|
+
// src/hooks/useViewerEffects.ts
|
|
19474
|
+
var import_react53 = require("react");
|
|
19475
|
+
var import_three25 = require("three");
|
|
19476
|
+
var NUMERIC_MATERIAL_KEYS = [
|
|
19477
|
+
"emissiveIntensity",
|
|
19478
|
+
"opacity",
|
|
19479
|
+
"metalness",
|
|
19480
|
+
"roughness",
|
|
19481
|
+
"transmission",
|
|
19482
|
+
"clearcoat",
|
|
19483
|
+
"clearcoatRoughness",
|
|
19484
|
+
"ior",
|
|
19485
|
+
"thickness"
|
|
19486
|
+
];
|
|
19487
|
+
var nextEffectId = 1;
|
|
19488
|
+
function stringList(target) {
|
|
19489
|
+
return typeof target === "string" ? [target] : target;
|
|
19490
|
+
}
|
|
19491
|
+
function clamp2(value, min = 0, max = 1) {
|
|
19492
|
+
return Math.min(max, Math.max(min, value));
|
|
19493
|
+
}
|
|
19494
|
+
function randomBetween(min, max) {
|
|
19495
|
+
return min + Math.random() * (max - min);
|
|
19496
|
+
}
|
|
19497
|
+
function interpolate([from, to], level) {
|
|
19498
|
+
return from + (to - from) * level;
|
|
19499
|
+
}
|
|
19500
|
+
function interpolateVector([from, to], level) {
|
|
19501
|
+
return [
|
|
19502
|
+
from[0] + (to[0] - from[0]) * level,
|
|
19503
|
+
from[1] + (to[1] - from[1]) * level,
|
|
19504
|
+
from[2] + (to[2] - from[2]) * level
|
|
19505
|
+
];
|
|
19506
|
+
}
|
|
19507
|
+
function ease(value, easing) {
|
|
19508
|
+
const t = clamp2(value);
|
|
19509
|
+
switch (easing) {
|
|
19510
|
+
case "ease-in":
|
|
19511
|
+
return t * t;
|
|
19512
|
+
case "ease-out":
|
|
19513
|
+
return 1 - (1 - t) * (1 - t);
|
|
19514
|
+
case "ease-in-out":
|
|
19515
|
+
return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
|
|
19516
|
+
default:
|
|
19517
|
+
return t;
|
|
19518
|
+
}
|
|
19519
|
+
}
|
|
19520
|
+
function materialList(node) {
|
|
19521
|
+
const value = node.material;
|
|
19522
|
+
if (!value) return [];
|
|
19523
|
+
return (Array.isArray(value) ? value : [value]).filter(
|
|
19524
|
+
(entry) => entry instanceof import_three25.Material
|
|
19525
|
+
);
|
|
19526
|
+
}
|
|
19527
|
+
function readMaterial(material2) {
|
|
19528
|
+
const snapshot = {
|
|
19529
|
+
opacity: material2.opacity,
|
|
19530
|
+
transparent: material2.transparent
|
|
19531
|
+
};
|
|
19532
|
+
if (material2.color) snapshot.baseColor = `#${material2.color.getHexString()}`;
|
|
19533
|
+
if (material2.emissive) snapshot.emissive = `#${material2.emissive.getHexString()}`;
|
|
19534
|
+
for (const key of NUMERIC_MATERIAL_KEYS) {
|
|
19535
|
+
const value = material2[key];
|
|
19536
|
+
if (typeof value === "number") snapshot[key] = value;
|
|
19537
|
+
}
|
|
19538
|
+
return snapshot;
|
|
19539
|
+
}
|
|
19540
|
+
function applyMaterial(material2, patch) {
|
|
19541
|
+
if (patch.baseColor !== void 0 && material2.color) {
|
|
19542
|
+
material2.color.set(patch.baseColor);
|
|
19543
|
+
}
|
|
19544
|
+
if (patch.emissive !== void 0 && material2.emissive) {
|
|
19545
|
+
material2.emissive.set(patch.emissive);
|
|
19546
|
+
}
|
|
19547
|
+
for (const key of NUMERIC_MATERIAL_KEYS) {
|
|
19548
|
+
const value = patch[key];
|
|
19549
|
+
if (value !== void 0 && typeof material2[key] === "number") {
|
|
19550
|
+
material2[key] = value;
|
|
19551
|
+
}
|
|
19552
|
+
}
|
|
19553
|
+
if (patch.transparent !== void 0) material2.transparent = patch.transparent;
|
|
19554
|
+
material2.needsUpdate = true;
|
|
19555
|
+
}
|
|
19556
|
+
function readTransform(node) {
|
|
19557
|
+
return {
|
|
19558
|
+
position: [node.position.x, node.position.y, node.position.z],
|
|
19559
|
+
rotation: [node.rotation.x, node.rotation.y, node.rotation.z],
|
|
19560
|
+
scale: [node.scale.x, node.scale.y, node.scale.z],
|
|
19561
|
+
visible: node.visible
|
|
19562
|
+
};
|
|
19563
|
+
}
|
|
19564
|
+
function applyTransform(node, patch) {
|
|
19565
|
+
if (patch.position) node.position.set(...patch.position);
|
|
19566
|
+
if (patch.rotation) node.rotation.set(...patch.rotation);
|
|
19567
|
+
if (patch.scale !== void 0) {
|
|
19568
|
+
const scale = typeof patch.scale === "number" ? [patch.scale, patch.scale, patch.scale] : patch.scale;
|
|
19569
|
+
node.scale.set(...scale);
|
|
19570
|
+
}
|
|
19571
|
+
if (patch.visible !== void 0) node.visible = patch.visible;
|
|
19572
|
+
node.updateMatrix();
|
|
19573
|
+
node.updateMatrixWorld(true);
|
|
19574
|
+
}
|
|
19575
|
+
function useViewerEffects(options = {}) {
|
|
19576
|
+
const optionsRef = (0, import_react53.useRef)(options);
|
|
19577
|
+
optionsRef.current = options;
|
|
19578
|
+
const viewerRef = (0, import_react53.useRef)(null);
|
|
19579
|
+
const sceneRef = (0, import_react53.useRef)(null);
|
|
19580
|
+
const frameRef = (0, import_react53.useRef)(null);
|
|
19581
|
+
const effectsRef = (0, import_react53.useRef)(/* @__PURE__ */ new Map());
|
|
19582
|
+
const lightsRef = (0, import_react53.useRef)(/* @__PURE__ */ new Map());
|
|
19583
|
+
const materialSnapshotsRef = (0, import_react53.useRef)(
|
|
19584
|
+
/* @__PURE__ */ new Map()
|
|
19585
|
+
);
|
|
19586
|
+
const transformSnapshotsRef = (0, import_react53.useRef)(/* @__PURE__ */ new Map());
|
|
19587
|
+
const resolveObject = (0, import_react53.useCallback)((target) => {
|
|
19588
|
+
const viewer = viewerRef.current;
|
|
19589
|
+
if (!viewer) return null;
|
|
19590
|
+
const bindingKey = resolveBindingKey(viewer.objectBindings, target);
|
|
19591
|
+
return viewer.nodeRefs[target] ?? (bindingKey ? viewer.nodeRefs[bindingKey] : null) ?? viewer.scene?.getObjectByName(target) ?? null;
|
|
19592
|
+
}, []);
|
|
19593
|
+
const resolveTargets = (0, import_react53.useCallback)(
|
|
19594
|
+
(target) => {
|
|
19595
|
+
const viewer = viewerRef.current;
|
|
19596
|
+
if (!viewer) {
|
|
19597
|
+
return typeof target === "string" ? [target] : Array.isArray(target) ? target : [];
|
|
19598
|
+
}
|
|
19599
|
+
if (typeof target === "object" && !Array.isArray(target)) {
|
|
19600
|
+
return selectBindingKeys(viewer.objectBindings, target);
|
|
19601
|
+
}
|
|
19602
|
+
return stringList(target).map(
|
|
19603
|
+
(id) => resolveBindingKey(viewer.objectBindings, id) ?? id
|
|
19604
|
+
);
|
|
19605
|
+
},
|
|
19606
|
+
[]
|
|
19607
|
+
);
|
|
19608
|
+
const invalidate = (0, import_react53.useCallback)(() => {
|
|
19609
|
+
viewerRef.current?.invalidate();
|
|
19610
|
+
}, []);
|
|
19611
|
+
const setMaterialInternal = (0, import_react53.useCallback)(
|
|
19612
|
+
(target, patch) => {
|
|
19613
|
+
let changed = false;
|
|
19614
|
+
for (const id of resolveTargets(target)) {
|
|
19615
|
+
const node = resolveObject(id);
|
|
19616
|
+
if (!node) continue;
|
|
19617
|
+
for (const entry of materialList(node)) {
|
|
19618
|
+
if (!materialSnapshotsRef.current.has(entry)) {
|
|
19619
|
+
materialSnapshotsRef.current.set(entry, readMaterial(entry));
|
|
19620
|
+
}
|
|
19621
|
+
applyMaterial(entry, patch);
|
|
19622
|
+
changed = true;
|
|
19623
|
+
}
|
|
19624
|
+
}
|
|
19625
|
+
return changed;
|
|
19626
|
+
},
|
|
19627
|
+
[resolveObject, resolveTargets]
|
|
19628
|
+
);
|
|
19629
|
+
const setMaterial = (0, import_react53.useCallback)(
|
|
19630
|
+
(target, patch) => {
|
|
19631
|
+
const changed = setMaterialInternal(target, patch);
|
|
19632
|
+
if (changed) invalidate();
|
|
19633
|
+
return changed;
|
|
19634
|
+
},
|
|
19635
|
+
[invalidate, setMaterialInternal]
|
|
19636
|
+
);
|
|
19637
|
+
const setTransformInternal = (0, import_react53.useCallback)(
|
|
19638
|
+
(target, patch) => {
|
|
19639
|
+
let changed = false;
|
|
19640
|
+
for (const id of resolveTargets(target)) {
|
|
19641
|
+
const node = resolveObject(id);
|
|
19642
|
+
if (!node) continue;
|
|
19643
|
+
if (!transformSnapshotsRef.current.has(node)) {
|
|
19644
|
+
transformSnapshotsRef.current.set(node, readTransform(node));
|
|
19645
|
+
}
|
|
19646
|
+
applyTransform(node, patch);
|
|
19647
|
+
changed = true;
|
|
19648
|
+
}
|
|
19649
|
+
return changed;
|
|
19650
|
+
},
|
|
19651
|
+
[resolveObject, resolveTargets]
|
|
19652
|
+
);
|
|
19653
|
+
const setTransform = (0, import_react53.useCallback)(
|
|
19654
|
+
(target, patch) => {
|
|
19655
|
+
const changed = setTransformInternal(target, patch);
|
|
19656
|
+
if (changed) invalidate();
|
|
19657
|
+
return changed;
|
|
19658
|
+
},
|
|
19659
|
+
[invalidate, setTransformInternal]
|
|
19660
|
+
);
|
|
19661
|
+
const getWorldPosition = (0, import_react53.useCallback)(
|
|
19662
|
+
(target) => {
|
|
19663
|
+
const node = resolveObject(target);
|
|
19664
|
+
if (!node) return null;
|
|
19665
|
+
node.updateWorldMatrix(true, false);
|
|
19666
|
+
const position = node.getWorldPosition(new import_three25.Vector3());
|
|
19667
|
+
return [position.x, position.y, position.z];
|
|
19668
|
+
},
|
|
19669
|
+
[resolveObject]
|
|
19670
|
+
);
|
|
19671
|
+
const removePointLight = (0, import_react53.useCallback)(
|
|
19672
|
+
(id) => {
|
|
19673
|
+
const runtime = lightsRef.current.get(id);
|
|
19674
|
+
if (!runtime) return false;
|
|
19675
|
+
runtime.light.removeFromParent();
|
|
19676
|
+
runtime.light.dispose();
|
|
19677
|
+
lightsRef.current.delete(id);
|
|
19678
|
+
invalidate();
|
|
19679
|
+
return true;
|
|
19680
|
+
},
|
|
19681
|
+
[invalidate]
|
|
19682
|
+
);
|
|
19683
|
+
const addPointLight = (0, import_react53.useCallback)(
|
|
19684
|
+
(lightOptions) => {
|
|
19685
|
+
const target = resolveObject(lightOptions.target);
|
|
19686
|
+
if (!target) return false;
|
|
19687
|
+
const existing = lightsRef.current.get(lightOptions.id);
|
|
19688
|
+
const light = existing?.light ?? new import_three25.PointLight();
|
|
19689
|
+
if (existing && existing.target !== lightOptions.target) {
|
|
19690
|
+
light.removeFromParent();
|
|
19691
|
+
}
|
|
19692
|
+
light.name = `react-immersive-runtime-light:${lightOptions.id}`;
|
|
19693
|
+
light.color.set(lightOptions.color ?? "#ffffff");
|
|
19694
|
+
light.intensity = lightOptions.intensity ?? 1;
|
|
19695
|
+
light.distance = lightOptions.distance ?? 0;
|
|
19696
|
+
light.decay = lightOptions.decay ?? 2;
|
|
19697
|
+
light.castShadow = lightOptions.castShadow ?? false;
|
|
19698
|
+
light.position.set(...lightOptions.offset ?? [0, 0, 0]);
|
|
19699
|
+
if (light.parent !== target) target.add(light);
|
|
19700
|
+
lightsRef.current.set(lightOptions.id, {
|
|
19701
|
+
light,
|
|
19702
|
+
target: lightOptions.target
|
|
19703
|
+
});
|
|
19704
|
+
invalidate();
|
|
19705
|
+
return true;
|
|
19706
|
+
},
|
|
19707
|
+
[invalidate, resolveObject]
|
|
19708
|
+
);
|
|
19709
|
+
const updatePointLight = (0, import_react53.useCallback)(
|
|
19710
|
+
(id, patch) => {
|
|
19711
|
+
const runtime = lightsRef.current.get(id);
|
|
19712
|
+
if (!runtime) return false;
|
|
19713
|
+
if (patch.target && patch.target !== runtime.target) {
|
|
19714
|
+
const target = resolveObject(patch.target);
|
|
19715
|
+
if (!target) return false;
|
|
19716
|
+
runtime.light.removeFromParent();
|
|
19717
|
+
target.add(runtime.light);
|
|
19718
|
+
runtime.target = patch.target;
|
|
19719
|
+
}
|
|
19720
|
+
if (patch.color !== void 0) runtime.light.color.set(patch.color);
|
|
19721
|
+
if (patch.intensity !== void 0) {
|
|
19722
|
+
runtime.light.intensity = patch.intensity;
|
|
19723
|
+
}
|
|
19724
|
+
if (patch.distance !== void 0) runtime.light.distance = patch.distance;
|
|
19725
|
+
if (patch.decay !== void 0) runtime.light.decay = patch.decay;
|
|
19726
|
+
if (patch.offset !== void 0) {
|
|
19727
|
+
runtime.light.position.set(...patch.offset);
|
|
19728
|
+
}
|
|
19729
|
+
if (patch.castShadow !== void 0) {
|
|
19730
|
+
runtime.light.castShadow = patch.castShadow;
|
|
19731
|
+
}
|
|
19732
|
+
invalidate();
|
|
19733
|
+
return true;
|
|
19734
|
+
},
|
|
19735
|
+
[invalidate, resolveObject]
|
|
19736
|
+
);
|
|
19737
|
+
const applyChannels = (0, import_react53.useCallback)(
|
|
19738
|
+
(channels, levels) => {
|
|
19739
|
+
const levelFor = (index) => levels[index % levels.length] ?? 0;
|
|
19740
|
+
for (const channel of channels.materials ?? []) {
|
|
19741
|
+
resolveTargets(channel.targets).forEach((target, index) => {
|
|
19742
|
+
const level = levelFor(index);
|
|
19743
|
+
const patch = {};
|
|
19744
|
+
for (const key of NUMERIC_MATERIAL_KEYS) {
|
|
19745
|
+
const range = channel.values[key];
|
|
19746
|
+
if (range) patch[key] = interpolate(range, level);
|
|
19747
|
+
}
|
|
19748
|
+
setMaterialInternal(target, patch);
|
|
19749
|
+
});
|
|
19750
|
+
}
|
|
19751
|
+
for (const channel of channels.transforms ?? []) {
|
|
19752
|
+
resolveTargets(channel.targets).forEach((target, index) => {
|
|
19753
|
+
const level = levelFor(index);
|
|
19754
|
+
const patch = {};
|
|
19755
|
+
if (channel.values.position) {
|
|
19756
|
+
patch.position = interpolateVector(channel.values.position, level);
|
|
19757
|
+
}
|
|
19758
|
+
if (channel.values.rotation) {
|
|
19759
|
+
patch.rotation = interpolateVector(channel.values.rotation, level);
|
|
19760
|
+
}
|
|
19761
|
+
if (channel.values.scale) {
|
|
19762
|
+
patch.scale = interpolateVector(channel.values.scale, level);
|
|
19763
|
+
}
|
|
19764
|
+
setTransformInternal(target, patch);
|
|
19765
|
+
});
|
|
19766
|
+
}
|
|
19767
|
+
for (const channel of channels.lights ?? []) {
|
|
19768
|
+
stringList(channel.lights).forEach((id, index) => {
|
|
19769
|
+
const runtime = lightsRef.current.get(id);
|
|
19770
|
+
if (runtime) {
|
|
19771
|
+
runtime.light.intensity = interpolate(
|
|
19772
|
+
channel.intensity,
|
|
19773
|
+
levelFor(index)
|
|
19774
|
+
);
|
|
19775
|
+
}
|
|
19776
|
+
});
|
|
19777
|
+
}
|
|
19778
|
+
},
|
|
19779
|
+
[resolveTargets, setMaterialInternal, setTransformInternal]
|
|
19780
|
+
);
|
|
19781
|
+
const scheduleFrameRef = (0, import_react53.useRef)(() => void 0);
|
|
19782
|
+
const runFrameRef = (0, import_react53.useRef)(() => void 0);
|
|
19783
|
+
runFrameRef.current = (now) => {
|
|
19784
|
+
frameRef.current = null;
|
|
19785
|
+
let rendered = false;
|
|
19786
|
+
for (const [id, effect] of effectsRef.current) {
|
|
19787
|
+
if (effect.startedAt === null) effect.startedAt = now;
|
|
19788
|
+
const previous = effect.lastFrameAt ?? now;
|
|
19789
|
+
effect.lastFrameAt = now;
|
|
19790
|
+
const override = effect.override && effect.override.until > now ? effect.override.level : null;
|
|
19791
|
+
if (effect.override && override === null) effect.override = null;
|
|
19792
|
+
const keepRunning = effect.update(
|
|
19793
|
+
now,
|
|
19794
|
+
now - effect.startedAt,
|
|
19795
|
+
Math.min(100, now - previous),
|
|
19796
|
+
override
|
|
19797
|
+
);
|
|
19798
|
+
rendered = true;
|
|
19799
|
+
if (!keepRunning) {
|
|
19800
|
+
effectsRef.current.delete(id);
|
|
19801
|
+
effect.onComplete?.();
|
|
19802
|
+
}
|
|
19803
|
+
}
|
|
19804
|
+
if (rendered) invalidate();
|
|
19805
|
+
if (effectsRef.current.size > 0) scheduleFrameRef.current();
|
|
19806
|
+
};
|
|
19807
|
+
scheduleFrameRef.current = () => {
|
|
19808
|
+
if (frameRef.current !== null || typeof requestAnimationFrame === "undefined") {
|
|
19809
|
+
return;
|
|
19810
|
+
}
|
|
19811
|
+
frameRef.current = requestAnimationFrame((now) => runFrameRef.current(now));
|
|
19812
|
+
};
|
|
19813
|
+
const registerEffect = (0, import_react53.useCallback)((effect) => {
|
|
19814
|
+
effectsRef.current.set(effect.id, effect);
|
|
19815
|
+
scheduleFrameRef.current();
|
|
19816
|
+
return effect.id;
|
|
19817
|
+
}, []);
|
|
19818
|
+
const transition = (0, import_react53.useCallback)(
|
|
19819
|
+
(channels, transitionOptions = {}) => {
|
|
19820
|
+
const id = transitionOptions.id ?? `transition-${nextEffectId++}`;
|
|
19821
|
+
const duration = Math.max(1, transitionOptions.duration ?? 400);
|
|
19822
|
+
const easing = transitionOptions.easing ?? "ease-in-out";
|
|
19823
|
+
return registerEffect({
|
|
19824
|
+
id,
|
|
19825
|
+
startedAt: null,
|
|
19826
|
+
lastFrameAt: null,
|
|
19827
|
+
override: null,
|
|
19828
|
+
onComplete: transitionOptions.onComplete,
|
|
19829
|
+
update: (_now, elapsed, _delta, override) => {
|
|
19830
|
+
const progress = override ?? ease(elapsed / duration, easing);
|
|
19831
|
+
applyChannels(channels, [progress]);
|
|
19832
|
+
return elapsed < duration;
|
|
19833
|
+
}
|
|
19834
|
+
});
|
|
19835
|
+
},
|
|
19836
|
+
[applyChannels, registerEffect]
|
|
19837
|
+
);
|
|
19838
|
+
const pulse = (0, import_react53.useCallback)(
|
|
19839
|
+
(channels, pulseOptions = {}) => {
|
|
19840
|
+
const id = pulseOptions.id ?? `pulse-${nextEffectId++}`;
|
|
19841
|
+
const duration = Math.max(1, pulseOptions.duration ?? 1e3);
|
|
19842
|
+
const minLevel = pulseOptions.minLevel ?? 0;
|
|
19843
|
+
const maxLevel = pulseOptions.maxLevel ?? 1;
|
|
19844
|
+
const repeat = pulseOptions.repeat ?? Infinity;
|
|
19845
|
+
const synchronized = pulseOptions.synchronized ?? true;
|
|
19846
|
+
const unitCount = Math.max(
|
|
19847
|
+
1,
|
|
19848
|
+
...[...channels.materials ?? [], ...channels.transforms ?? []].map(
|
|
19849
|
+
(channel) => resolveTargets(channel.targets).length
|
|
19850
|
+
),
|
|
19851
|
+
...(channels.lights ?? []).map(
|
|
19852
|
+
(channel) => stringList(channel.lights).length
|
|
19853
|
+
)
|
|
19854
|
+
);
|
|
19855
|
+
return registerEffect({
|
|
19856
|
+
id,
|
|
19857
|
+
startedAt: null,
|
|
19858
|
+
lastFrameAt: null,
|
|
19859
|
+
override: null,
|
|
19860
|
+
onComplete: pulseOptions.onComplete,
|
|
19861
|
+
update: (_now, elapsed, _delta, override) => {
|
|
19862
|
+
const cycles = elapsed / duration;
|
|
19863
|
+
const levels = Array.from(
|
|
19864
|
+
{ length: synchronized ? 1 : unitCount },
|
|
19865
|
+
(_, index) => {
|
|
19866
|
+
if (override !== null) return override;
|
|
19867
|
+
const phase = cycles + (synchronized ? 0 : index / unitCount);
|
|
19868
|
+
const wave = 0.5 - Math.cos(phase % 1 * Math.PI * 2) / 2;
|
|
19869
|
+
return minLevel + (maxLevel - minLevel) * wave;
|
|
19870
|
+
}
|
|
19871
|
+
);
|
|
19872
|
+
applyChannels(channels, levels);
|
|
19873
|
+
return repeat === Infinity || cycles < repeat;
|
|
19874
|
+
}
|
|
19875
|
+
});
|
|
19876
|
+
},
|
|
19877
|
+
[applyChannels, registerEffect, resolveTargets]
|
|
19878
|
+
);
|
|
19879
|
+
const timeline = (0, import_react53.useCallback)(
|
|
19880
|
+
(steps, timelineOptions = {}) => {
|
|
19881
|
+
const id = timelineOptions.id ?? `timeline-${nextEffectId++}`;
|
|
19882
|
+
const repeat = timelineOptions.repeat ?? 1;
|
|
19883
|
+
const normalizedSteps = steps.map((step) => ({
|
|
19884
|
+
...step,
|
|
19885
|
+
duration: Math.max(1, step.duration),
|
|
19886
|
+
hold: Math.max(0, step.hold ?? 0)
|
|
19887
|
+
}));
|
|
19888
|
+
const cycleDuration = Math.max(
|
|
19889
|
+
1,
|
|
19890
|
+
normalizedSteps.reduce(
|
|
19891
|
+
(total, step) => total + step.duration + step.hold,
|
|
19892
|
+
0
|
|
19893
|
+
)
|
|
19894
|
+
);
|
|
19895
|
+
return registerEffect({
|
|
19896
|
+
id,
|
|
19897
|
+
startedAt: null,
|
|
19898
|
+
lastFrameAt: null,
|
|
19899
|
+
override: null,
|
|
19900
|
+
onComplete: timelineOptions.onComplete,
|
|
19901
|
+
update: (_now, elapsed, _delta, override) => {
|
|
19902
|
+
if (normalizedSteps.length === 0 || repeat <= 0) return false;
|
|
19903
|
+
const cycles = elapsed / cycleDuration;
|
|
19904
|
+
if (repeat !== Infinity && cycles >= repeat) {
|
|
19905
|
+
for (const step of normalizedSteps) {
|
|
19906
|
+
applyChannels(step.channels, [1]);
|
|
19907
|
+
}
|
|
19908
|
+
return false;
|
|
19909
|
+
}
|
|
19910
|
+
const cycleTime = elapsed % cycleDuration;
|
|
19911
|
+
let cursor = 0;
|
|
19912
|
+
for (const step of normalizedSteps) {
|
|
19913
|
+
const transitionEnd = cursor + step.duration;
|
|
19914
|
+
const stepEnd = transitionEnd + step.hold;
|
|
19915
|
+
if (cycleTime >= transitionEnd) {
|
|
19916
|
+
applyChannels(step.channels, [override ?? 1]);
|
|
19917
|
+
cursor = stepEnd;
|
|
19918
|
+
continue;
|
|
19919
|
+
}
|
|
19920
|
+
if (cycleTime >= cursor) {
|
|
19921
|
+
const progress = override ?? ease(
|
|
19922
|
+
(cycleTime - cursor) / step.duration,
|
|
19923
|
+
step.easing ?? "ease-in-out"
|
|
19924
|
+
);
|
|
19925
|
+
applyChannels(step.channels, [progress]);
|
|
19926
|
+
break;
|
|
19927
|
+
}
|
|
19928
|
+
}
|
|
19929
|
+
return true;
|
|
19930
|
+
}
|
|
19931
|
+
});
|
|
19932
|
+
},
|
|
19933
|
+
[applyChannels, registerEffect]
|
|
19934
|
+
);
|
|
19935
|
+
const flicker = (0, import_react53.useCallback)(
|
|
19936
|
+
(channels, flickerOptions = {}) => {
|
|
19937
|
+
const id = flickerOptions.id ?? `flicker-${nextEffectId++}`;
|
|
19938
|
+
const synchronized = flickerOptions.synchronized ?? true;
|
|
19939
|
+
const minLevel = flickerOptions.minLevel ?? 0.15;
|
|
19940
|
+
const maxLevel = flickerOptions.maxLevel ?? 1;
|
|
19941
|
+
const interval = flickerOptions.interval ?? [45, 160];
|
|
19942
|
+
const rawIntervalRange = typeof interval === "number" ? [interval, interval] : interval;
|
|
19943
|
+
const intervalRange = [
|
|
19944
|
+
Math.max(1, Math.min(...rawIntervalRange)),
|
|
19945
|
+
Math.max(1, Math.max(...rawIntervalRange))
|
|
19946
|
+
];
|
|
19947
|
+
const response = clamp2(flickerOptions.response ?? 0.7, 0.01, 1);
|
|
19948
|
+
const blackoutChance = clamp2(flickerOptions.blackoutChance ?? 0.08);
|
|
19949
|
+
const flashChance = clamp2(flickerOptions.flashChance ?? 0.12);
|
|
19950
|
+
const flashLevel = flickerOptions.flashLevel ?? 1.15;
|
|
19951
|
+
const unitCount = Math.max(
|
|
19952
|
+
1,
|
|
19953
|
+
...[...channels.materials ?? [], ...channels.transforms ?? []].map(
|
|
19954
|
+
(channel) => resolveTargets(channel.targets).length
|
|
19955
|
+
),
|
|
19956
|
+
...(channels.lights ?? []).map(
|
|
19957
|
+
(channel) => stringList(channel.lights).length
|
|
19958
|
+
)
|
|
19959
|
+
);
|
|
19960
|
+
const count = synchronized ? 1 : unitCount;
|
|
19961
|
+
const levels = Array.from({ length: count }, () => minLevel);
|
|
19962
|
+
const targets = Array.from({ length: count }, () => minLevel);
|
|
19963
|
+
const nextChanges = Array.from({ length: count }, () => 0);
|
|
19964
|
+
return registerEffect({
|
|
19965
|
+
id,
|
|
19966
|
+
startedAt: null,
|
|
19967
|
+
lastFrameAt: null,
|
|
19968
|
+
override: null,
|
|
19969
|
+
onComplete: flickerOptions.onComplete,
|
|
19970
|
+
update: (now, elapsed, delta, override) => {
|
|
19971
|
+
for (let index = 0; index < count; index += 1) {
|
|
19972
|
+
if (override !== null) {
|
|
19973
|
+
targets[index] = override;
|
|
19974
|
+
} else if (now >= nextChanges[index]) {
|
|
19975
|
+
const roll = Math.random();
|
|
19976
|
+
targets[index] = roll < blackoutChance ? randomBetween(0, Math.min(0.04, minLevel)) : roll < blackoutChance + flashChance ? flashLevel : randomBetween(minLevel, maxLevel);
|
|
19977
|
+
nextChanges[index] = now + randomBetween(...intervalRange);
|
|
19978
|
+
}
|
|
19979
|
+
const frameResponse = 1 - Math.pow(1 - response, Math.max(1, delta) / 16.67);
|
|
19980
|
+
levels[index] += (targets[index] - levels[index]) * frameResponse;
|
|
19981
|
+
}
|
|
19982
|
+
applyChannels(channels, levels);
|
|
19983
|
+
return flickerOptions.duration === void 0 || elapsed < flickerOptions.duration;
|
|
19984
|
+
}
|
|
19985
|
+
});
|
|
19986
|
+
},
|
|
19987
|
+
[applyChannels, registerEffect, resolveTargets]
|
|
19988
|
+
);
|
|
19989
|
+
const overrideEffect = (0, import_react53.useCallback)(
|
|
19990
|
+
(id, level, duration) => {
|
|
19991
|
+
const effect = effectsRef.current.get(id);
|
|
19992
|
+
if (!effect) return false;
|
|
19993
|
+
const now = typeof performance === "undefined" ? Date.now() : performance.now();
|
|
19994
|
+
effect.override = { level, until: now + Math.max(0, duration) };
|
|
19995
|
+
scheduleFrameRef.current();
|
|
19996
|
+
return true;
|
|
19997
|
+
},
|
|
19998
|
+
[]
|
|
19999
|
+
);
|
|
20000
|
+
const stopEffect = (0, import_react53.useCallback)((id) => {
|
|
20001
|
+
return effectsRef.current.delete(id);
|
|
20002
|
+
}, []);
|
|
20003
|
+
const stopAllEffects = (0, import_react53.useCallback)(() => {
|
|
20004
|
+
effectsRef.current.clear();
|
|
20005
|
+
if (frameRef.current !== null && typeof cancelAnimationFrame !== "undefined") {
|
|
20006
|
+
cancelAnimationFrame(frameRef.current);
|
|
20007
|
+
frameRef.current = null;
|
|
20008
|
+
}
|
|
20009
|
+
}, []);
|
|
20010
|
+
const restoreRuntimeValues = (0, import_react53.useCallback)(() => {
|
|
20011
|
+
for (const [entry, snapshot] of materialSnapshotsRef.current) {
|
|
20012
|
+
applyMaterial(entry, snapshot);
|
|
20013
|
+
}
|
|
20014
|
+
materialSnapshotsRef.current.clear();
|
|
20015
|
+
for (const [node, snapshot] of transformSnapshotsRef.current) {
|
|
20016
|
+
node.position.set(...snapshot.position);
|
|
20017
|
+
node.rotation.set(...snapshot.rotation);
|
|
20018
|
+
node.scale.set(...snapshot.scale);
|
|
20019
|
+
node.visible = snapshot.visible;
|
|
20020
|
+
node.updateMatrix();
|
|
20021
|
+
node.updateMatrixWorld(true);
|
|
20022
|
+
}
|
|
20023
|
+
transformSnapshotsRef.current.clear();
|
|
20024
|
+
for (const runtime of lightsRef.current.values()) {
|
|
20025
|
+
runtime.light.removeFromParent();
|
|
20026
|
+
runtime.light.dispose();
|
|
20027
|
+
}
|
|
20028
|
+
lightsRef.current.clear();
|
|
20029
|
+
invalidate();
|
|
20030
|
+
}, [invalidate]);
|
|
20031
|
+
const resetRuntime = (0, import_react53.useCallback)(() => {
|
|
20032
|
+
stopAllEffects();
|
|
20033
|
+
restoreRuntimeValues();
|
|
20034
|
+
}, [restoreRuntimeValues, stopAllEffects]);
|
|
20035
|
+
const handleViewerReady = (0, import_react53.useCallback)(
|
|
20036
|
+
(viewer) => {
|
|
20037
|
+
if (sceneRef.current && sceneRef.current !== viewer.scene) {
|
|
20038
|
+
restoreRuntimeValues();
|
|
20039
|
+
}
|
|
20040
|
+
viewerRef.current = viewer;
|
|
20041
|
+
sceneRef.current = viewer.scene;
|
|
20042
|
+
optionsRef.current.onViewerReady?.(viewer);
|
|
20043
|
+
},
|
|
20044
|
+
[restoreRuntimeValues]
|
|
20045
|
+
);
|
|
20046
|
+
(0, import_react53.useEffect)(() => {
|
|
20047
|
+
return () => {
|
|
20048
|
+
resetRuntime();
|
|
20049
|
+
viewerRef.current = null;
|
|
20050
|
+
sceneRef.current = null;
|
|
20051
|
+
};
|
|
20052
|
+
}, [resetRuntime]);
|
|
20053
|
+
return {
|
|
20054
|
+
handleViewerReady,
|
|
20055
|
+
setMaterial,
|
|
20056
|
+
setTransform,
|
|
20057
|
+
getWorldPosition,
|
|
20058
|
+
addPointLight,
|
|
20059
|
+
updatePointLight,
|
|
20060
|
+
removePointLight,
|
|
20061
|
+
transition,
|
|
20062
|
+
timeline,
|
|
20063
|
+
pulse,
|
|
20064
|
+
flicker,
|
|
20065
|
+
overrideEffect,
|
|
20066
|
+
stopEffect,
|
|
20067
|
+
stopAllEffects,
|
|
20068
|
+
resetRuntime
|
|
20069
|
+
};
|
|
20070
|
+
}
|
|
20071
|
+
|
|
18777
20072
|
// src/hooks/useShareableViewerState.ts
|
|
18778
|
-
var
|
|
20073
|
+
var import_react54 = require("react");
|
|
18779
20074
|
function serializeState(cameraState, objectBindings, selectedObjectBinding) {
|
|
18780
20075
|
const hidden = Object.values(objectBindings).filter((binding) => binding.visible === false).map((binding) => binding.id);
|
|
18781
20076
|
return {
|
|
@@ -18795,8 +20090,8 @@ function useShareableViewerState({
|
|
|
18795
20090
|
debounceMs = 400,
|
|
18796
20091
|
autoSync = true
|
|
18797
20092
|
}) {
|
|
18798
|
-
const lastWrittenRawRef = (0,
|
|
18799
|
-
const buildHash = (0,
|
|
20093
|
+
const lastWrittenRawRef = (0, import_react54.useRef)(null);
|
|
20094
|
+
const buildHash = (0, import_react54.useCallback)(() => {
|
|
18800
20095
|
const state = serializeState(
|
|
18801
20096
|
cameraState,
|
|
18802
20097
|
objectBindings,
|
|
@@ -18804,12 +20099,12 @@ function useShareableViewerState({
|
|
|
18804
20099
|
);
|
|
18805
20100
|
return `${paramKey}=${encodeURIComponent(JSON.stringify(state))}`;
|
|
18806
20101
|
}, [cameraState, objectBindings, selectedObjectBinding, paramKey]);
|
|
18807
|
-
const getShareUrl = (0,
|
|
20102
|
+
const getShareUrl = (0, import_react54.useCallback)(() => {
|
|
18808
20103
|
const url = new URL(window.location.href);
|
|
18809
20104
|
url.hash = buildHash();
|
|
18810
20105
|
return url.toString();
|
|
18811
20106
|
}, [buildHash]);
|
|
18812
|
-
const syncUrl = (0,
|
|
20107
|
+
const syncUrl = (0, import_react54.useCallback)(() => {
|
|
18813
20108
|
const url = new URL(window.location.href);
|
|
18814
20109
|
url.hash = buildHash();
|
|
18815
20110
|
window.history.replaceState(null, "", url.toString());
|
|
@@ -18817,7 +20112,7 @@ function useShareableViewerState({
|
|
|
18817
20112
|
paramKey
|
|
18818
20113
|
);
|
|
18819
20114
|
}, [buildHash, paramKey]);
|
|
18820
|
-
const latestStateRef = (0,
|
|
20115
|
+
const latestStateRef = (0, import_react54.useRef)({
|
|
18821
20116
|
cameraState,
|
|
18822
20117
|
objectBindings,
|
|
18823
20118
|
selectedObjectBinding
|
|
@@ -18827,9 +20122,9 @@ function useShareableViewerState({
|
|
|
18827
20122
|
objectBindings,
|
|
18828
20123
|
selectedObjectBinding
|
|
18829
20124
|
};
|
|
18830
|
-
const [restoreAttempted, setRestoreAttempted] = (0,
|
|
18831
|
-
const lastSyncedHashRef = (0,
|
|
18832
|
-
(0,
|
|
20125
|
+
const [restoreAttempted, setRestoreAttempted] = (0, import_react54.useState)(false);
|
|
20126
|
+
const lastSyncedHashRef = (0, import_react54.useRef)(null);
|
|
20127
|
+
(0, import_react54.useEffect)(() => {
|
|
18833
20128
|
if (!autoSync || !restoreAttempted) return;
|
|
18834
20129
|
const tick = () => {
|
|
18835
20130
|
const current = latestStateRef.current;
|
|
@@ -18851,9 +20146,9 @@ function useShareableViewerState({
|
|
|
18851
20146
|
const id = window.setInterval(tick, debounceMs);
|
|
18852
20147
|
return () => window.clearInterval(id);
|
|
18853
20148
|
}, [autoSync, restoreAttempted, debounceMs, paramKey]);
|
|
18854
|
-
const lastRestoredRawRef = (0,
|
|
18855
|
-
const restoringRawRef = (0,
|
|
18856
|
-
const restoreFromUrl = (0,
|
|
20149
|
+
const lastRestoredRawRef = (0, import_react54.useRef)(null);
|
|
20150
|
+
const restoringRawRef = (0, import_react54.useRef)(null);
|
|
20151
|
+
const restoreFromUrl = (0, import_react54.useCallback)(async () => {
|
|
18857
20152
|
setRestoreAttempted(true);
|
|
18858
20153
|
const rawHash = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : window.location.hash;
|
|
18859
20154
|
const raw = new URLSearchParams(rawHash).get(paramKey);
|
|
@@ -18906,7 +20201,7 @@ function useShareableViewerState({
|
|
|
18906
20201
|
setCameraState,
|
|
18907
20202
|
setSelectedObjectBinding
|
|
18908
20203
|
]);
|
|
18909
|
-
(0,
|
|
20204
|
+
(0, import_react54.useEffect)(() => {
|
|
18910
20205
|
const handleHashChange = () => {
|
|
18911
20206
|
void restoreFromUrl();
|
|
18912
20207
|
};
|
|
@@ -18920,13 +20215,17 @@ function useShareableViewerState({
|
|
|
18920
20215
|
// Annotate the CommonJS export names for ESM import in node:
|
|
18921
20216
|
0 && (module.exports = {
|
|
18922
20217
|
BindingBuilder,
|
|
20218
|
+
DEFAULT_SCENE_CONFIG,
|
|
18923
20219
|
MATERIAL_BLENDING_MODES,
|
|
18924
20220
|
MATERIAL_SIDES,
|
|
18925
20221
|
ModelViewer,
|
|
18926
20222
|
SimpleModelViewer,
|
|
20223
|
+
defineObjectBindings,
|
|
18927
20224
|
material,
|
|
18928
20225
|
patchBindings,
|
|
18929
20226
|
patchSceneConfig,
|
|
20227
|
+
selectBindingKeys,
|
|
20228
|
+
selectBindings,
|
|
18930
20229
|
useObjectBinding,
|
|
18931
20230
|
useObjectBindingIds,
|
|
18932
20231
|
useObjectBindings,
|
|
@@ -18935,6 +20234,8 @@ function useShareableViewerState({
|
|
|
18935
20234
|
useViewerActions,
|
|
18936
20235
|
useViewerAnimations,
|
|
18937
20236
|
useViewerCamera,
|
|
20237
|
+
useViewerConnection,
|
|
20238
|
+
useViewerEffects,
|
|
18938
20239
|
useViewerHover,
|
|
18939
20240
|
useViewerModel,
|
|
18940
20241
|
useViewerSelection
|