@almadar/ui 5.142.0 → 5.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +173 -35
- package/dist/avl/index.js +174 -36
- package/dist/{avl-schema-parser-DAs12kxP.d.ts → avl-schema-parser-BRJ77Yze.d.ts} +17 -3
- package/dist/{avl-schema-parser-wOkfbwAh.d.cts → avl-schema-parser-DVmrgdwc.d.cts} +17 -3
- package/dist/{cn-rwc3svaX.d.cts → cn-BdGFhYe3.d.cts} +1 -1
- package/dist/{cn-BDwC4QpH.d.ts → cn-DNkqAWZK.d.ts} +1 -1
- package/dist/components/index.cjs +277 -163
- package/dist/components/index.d.cts +9 -7
- package/dist/components/index.d.ts +9 -7
- package/dist/components/index.js +278 -164
- package/dist/lib/drawable/three/index.cjs +449 -195
- package/dist/lib/drawable/three/index.d.cts +3 -3
- package/dist/lib/drawable/three/index.d.ts +3 -3
- package/dist/lib/drawable/three/index.js +425 -171
- package/dist/lib/index.d.cts +2 -2
- package/dist/lib/index.d.ts +2 -2
- package/dist/marketing/index.cjs +6 -1
- package/dist/marketing/index.js +6 -1
- package/dist/{paintDispatch-BQn5Lyx1.d.cts → paintDispatch-Cb_hQj4Y.d.cts} +79 -33
- package/dist/{paintDispatch-BQn5Lyx1.d.ts → paintDispatch-Cb_hQj4Y.d.ts} +79 -33
- package/dist/providers/index.cjs +173 -35
- package/dist/providers/index.js +174 -36
- package/dist/runtime/index.cjs +173 -35
- package/dist/runtime/index.js +174 -36
- package/package.json +9 -8
|
@@ -4,7 +4,7 @@ var React3 = require('react');
|
|
|
4
4
|
var providers = require('@almadar/ui/providers');
|
|
5
5
|
var logger = require('@almadar/logger');
|
|
6
6
|
var fiber = require('@react-three/fiber');
|
|
7
|
-
var
|
|
7
|
+
var THREE5 = require('three');
|
|
8
8
|
var RoomEnvironment_js = require('three/examples/jsm/environments/RoomEnvironment.js');
|
|
9
9
|
var drei = require('@react-three/drei');
|
|
10
10
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -39,7 +39,7 @@ function _interopNamespace(e) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
42
|
-
var
|
|
42
|
+
var THREE5__namespace = /*#__PURE__*/_interopNamespace(THREE5);
|
|
43
43
|
|
|
44
44
|
var __defProp = Object.defineProperty;
|
|
45
45
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -531,7 +531,7 @@ function Lighting3D({
|
|
|
531
531
|
"directionalLightHelper",
|
|
532
532
|
{
|
|
533
533
|
args: [
|
|
534
|
-
new
|
|
534
|
+
new THREE5__namespace.DirectionalLight(directionalColor, directionalIntensity),
|
|
535
535
|
5
|
|
536
536
|
]
|
|
537
537
|
}
|
|
@@ -588,8 +588,8 @@ function FollowCamera3D({
|
|
|
588
588
|
offset
|
|
589
589
|
}) {
|
|
590
590
|
const { camera } = fiber.useThree();
|
|
591
|
-
const look = React3.useRef(new
|
|
592
|
-
const goal = React3.useRef(new
|
|
591
|
+
const look = React3.useRef(new THREE5__namespace.Vector3(target[0], target[1], target[2]));
|
|
592
|
+
const goal = React3.useRef(new THREE5__namespace.Vector3());
|
|
593
593
|
fiber.useFrame((_, delta) => {
|
|
594
594
|
const t = Math.min(1, delta * 5);
|
|
595
595
|
goal.current.set(target[0] + offset[0], target[1] + offset[1], target[2] + offset[2]);
|
|
@@ -610,7 +610,109 @@ function create3DProjector(opts = {}) {
|
|
|
610
610
|
toWorld: (pos) => [pos.x * cellSize + offsetX, pos.z ?? 0, pos.y * cellSize + offsetZ]
|
|
611
611
|
};
|
|
612
612
|
}
|
|
613
|
+
var BoneStore = class {
|
|
614
|
+
constructor() {
|
|
615
|
+
__publicField(this, "bones", /* @__PURE__ */ new Map());
|
|
616
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
617
|
+
}
|
|
618
|
+
register(name, bone) {
|
|
619
|
+
this.bones.set(name, bone);
|
|
620
|
+
this.notify();
|
|
621
|
+
return () => {
|
|
622
|
+
if (this.bones.get(name) === bone) {
|
|
623
|
+
this.bones.delete(name);
|
|
624
|
+
this.notify();
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
get(name) {
|
|
629
|
+
return this.bones.get(name);
|
|
630
|
+
}
|
|
631
|
+
subscribe(listener) {
|
|
632
|
+
this.listeners.add(listener);
|
|
633
|
+
return () => this.listeners.delete(listener);
|
|
634
|
+
}
|
|
635
|
+
notify() {
|
|
636
|
+
for (const l of this.listeners) l();
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
var BoneRegistryContext = React3.createContext(null);
|
|
640
|
+
function isAnimatedGroup(node) {
|
|
641
|
+
return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
|
|
642
|
+
}
|
|
643
|
+
var MESH_SEGMENTS_DEFAULT = 24;
|
|
644
|
+
function polyhedronBounds(vertices) {
|
|
645
|
+
if (!vertices || vertices.length < 3) return null;
|
|
646
|
+
const min = [Infinity, Infinity, Infinity];
|
|
647
|
+
const max = [-Infinity, -Infinity, -Infinity];
|
|
648
|
+
for (const v of vertices) {
|
|
649
|
+
if (v.length < 3 || !v.every((c) => Number.isFinite(c))) return null;
|
|
650
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
651
|
+
min[axis] = Math.min(min[axis], v[axis]);
|
|
652
|
+
max[axis] = Math.max(max[axis], v[axis]);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return { min, max };
|
|
656
|
+
}
|
|
657
|
+
function clampSegments(segments) {
|
|
658
|
+
const s = segments ?? MESH_SEGMENTS_DEFAULT;
|
|
659
|
+
return Math.min(64, Math.max(3, Math.round(s)));
|
|
660
|
+
}
|
|
661
|
+
function isAnimatedMesh(node) {
|
|
662
|
+
return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
|
|
663
|
+
}
|
|
664
|
+
var lerp = (a, b, k) => a + (b - a) * k;
|
|
613
665
|
var NUMERIC_TRACKS = [
|
|
666
|
+
"offsetX",
|
|
667
|
+
"offsetY",
|
|
668
|
+
"offsetZ",
|
|
669
|
+
"rotateX",
|
|
670
|
+
"rotateY",
|
|
671
|
+
"rotateZ",
|
|
672
|
+
"scale",
|
|
673
|
+
"opacity",
|
|
674
|
+
"emissiveIntensity"
|
|
675
|
+
];
|
|
676
|
+
function applyMeshAnimation(node, timeMs) {
|
|
677
|
+
const anim = node.animation;
|
|
678
|
+
if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
|
|
679
|
+
const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
|
|
680
|
+
const cycle = timeMs / anim.durationMs;
|
|
681
|
+
const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
|
|
682
|
+
const trackValue = (key) => {
|
|
683
|
+
const defined = frames.filter((f) => f[key] !== void 0);
|
|
684
|
+
if (defined.length === 0) return void 0;
|
|
685
|
+
let prev;
|
|
686
|
+
let next;
|
|
687
|
+
for (const f of defined) {
|
|
688
|
+
if (f.at <= t) prev = f;
|
|
689
|
+
else if (!next) next = f;
|
|
690
|
+
}
|
|
691
|
+
if (!prev) return defined[0][key];
|
|
692
|
+
if (!next) return prev[key];
|
|
693
|
+
const span = next.at - prev.at;
|
|
694
|
+
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
695
|
+
const a = prev[key];
|
|
696
|
+
const b = next[key];
|
|
697
|
+
if (typeof a === "number" && typeof b === "number") return lerp(a, b, k);
|
|
698
|
+
return a;
|
|
699
|
+
};
|
|
700
|
+
const num = {};
|
|
701
|
+
for (const key of NUMERIC_TRACKS) {
|
|
702
|
+
const v = trackValue(key);
|
|
703
|
+
if (v !== void 0) num[key] = v;
|
|
704
|
+
}
|
|
705
|
+
return {
|
|
706
|
+
offset: [num.offsetX ?? 0, num.offsetY ?? 0, num.offsetZ ?? 0],
|
|
707
|
+
rotate: [num.rotateX ?? 0, num.rotateY ?? 0, num.rotateZ ?? 0],
|
|
708
|
+
scale: num.scale ?? 1,
|
|
709
|
+
opacity: num.opacity,
|
|
710
|
+
emissiveIntensity: num.emissiveIntensity,
|
|
711
|
+
color: trackValue("color"),
|
|
712
|
+
emissive: trackValue("emissive")
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
var NUMERIC_TRACKS2 = [
|
|
614
716
|
"offsetX",
|
|
615
717
|
"offsetY",
|
|
616
718
|
"rotate",
|
|
@@ -626,7 +728,7 @@ var NUMERIC_TRACKS = [
|
|
|
626
728
|
function isAnimatedShape(node) {
|
|
627
729
|
return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
|
|
628
730
|
}
|
|
629
|
-
var
|
|
731
|
+
var lerp2 = (a, b, k) => a + (b - a) * k;
|
|
630
732
|
function applyShapeAnimation(node, timeMs) {
|
|
631
733
|
const anim = node.animation;
|
|
632
734
|
if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return node;
|
|
@@ -649,10 +751,10 @@ function applyShapeAnimation(node, timeMs) {
|
|
|
649
751
|
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
650
752
|
const a = prev[key];
|
|
651
753
|
const b = next[key];
|
|
652
|
-
if (typeof a === "number" && typeof b === "number") return
|
|
754
|
+
if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
|
|
653
755
|
return a;
|
|
654
756
|
};
|
|
655
|
-
for (const key of
|
|
757
|
+
for (const key of NUMERIC_TRACKS2) {
|
|
656
758
|
const v = trackValue(key);
|
|
657
759
|
if (v !== void 0) out[key] = v;
|
|
658
760
|
}
|
|
@@ -673,7 +775,7 @@ function applyShapeAnimation(node, timeMs) {
|
|
|
673
775
|
if (prevSh?.shadow && nextSh?.shadow) {
|
|
674
776
|
const span = nextSh.at - prevSh.at;
|
|
675
777
|
const k = span > 0 ? (t - prevSh.at) / span : 1;
|
|
676
|
-
out.shadow = { color: prevSh.shadow.color, blur:
|
|
778
|
+
out.shadow = { color: prevSh.shadow.color, blur: lerp2(prevSh.shadow.blur, nextSh.shadow.blur, k) };
|
|
677
779
|
} else {
|
|
678
780
|
out.shadow = sh;
|
|
679
781
|
}
|
|
@@ -687,6 +789,10 @@ var atlasCache = /* @__PURE__ */ new Map();
|
|
|
687
789
|
function isTilesheet(a) {
|
|
688
790
|
return typeof a.tileWidth === "number";
|
|
689
791
|
}
|
|
792
|
+
function isSpriteSheetAtlas(a) {
|
|
793
|
+
const s = a;
|
|
794
|
+
return typeof s.frameWidth === "number" && typeof s.frameHeight === "number" && typeof s.animations === "object";
|
|
795
|
+
}
|
|
690
796
|
function getAtlas(url, onReady) {
|
|
691
797
|
if (atlasCache.has(url)) return atlasCache.get(url) ?? void 0;
|
|
692
798
|
atlasCache.set(url, void 0);
|
|
@@ -723,6 +829,7 @@ function subRectFor(atlas, sprite) {
|
|
|
723
829
|
sh: atlas.tileHeight
|
|
724
830
|
};
|
|
725
831
|
}
|
|
832
|
+
if (isSpriteSheetAtlas(atlas)) return null;
|
|
726
833
|
const st = atlas.subTextures[sprite];
|
|
727
834
|
if (!st) return null;
|
|
728
835
|
return { sx: st.x, sy: st.y, sw: st.width, sh: st.height };
|
|
@@ -816,12 +923,12 @@ function ModelLoader({
|
|
|
816
923
|
if (!loadedModel) return null;
|
|
817
924
|
const cloned = SkeletonUtils.clone(loadedModel);
|
|
818
925
|
cloned.updateMatrixWorld(true);
|
|
819
|
-
const tintColor = tint ? new
|
|
926
|
+
const tintColor = tint ? new THREE5__namespace.Color(tint) : null;
|
|
820
927
|
cloned.traverse((child) => {
|
|
821
|
-
if (child instanceof
|
|
928
|
+
if (child instanceof THREE5__namespace.Mesh) {
|
|
822
929
|
child.castShadow = castShadow;
|
|
823
930
|
child.receiveShadow = receiveShadow;
|
|
824
|
-
if (tintColor && child.material instanceof
|
|
931
|
+
if (tintColor && child.material instanceof THREE5__namespace.MeshStandardMaterial) {
|
|
825
932
|
const mat = child.material.clone();
|
|
826
933
|
mat.color.multiply(tintColor);
|
|
827
934
|
child.material = mat;
|
|
@@ -830,7 +937,7 @@ function ModelLoader({
|
|
|
830
937
|
});
|
|
831
938
|
return cloned;
|
|
832
939
|
}, [loadedModel, castShadow, receiveShadow, tint]);
|
|
833
|
-
const mixer = React3.useMemo(() => model ? new
|
|
940
|
+
const mixer = React3.useMemo(() => model ? new THREE5__namespace.AnimationMixer(model) : null, [model]);
|
|
834
941
|
React3.useEffect(() => {
|
|
835
942
|
if (!mixer || !animation || clips.length === 0) return;
|
|
836
943
|
const wanted = animation.toLowerCase();
|
|
@@ -847,8 +954,8 @@ function ModelLoader({
|
|
|
847
954
|
});
|
|
848
955
|
const normFactor = React3.useMemo(() => {
|
|
849
956
|
if (!model) return 1;
|
|
850
|
-
const box = new
|
|
851
|
-
const size = new
|
|
957
|
+
const box = new THREE5__namespace.Box3().setFromObject(model);
|
|
958
|
+
const size = new THREE5__namespace.Vector3();
|
|
852
959
|
box.getSize(size);
|
|
853
960
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
854
961
|
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
@@ -938,7 +1045,7 @@ var warnUnsupported3d = (kind) => {
|
|
|
938
1045
|
warnedUnsupported.add(kind);
|
|
939
1046
|
mesh3dLog.warn("unsupported drawable kind on the 3D backend \u2014 skipped", { kind });
|
|
940
1047
|
};
|
|
941
|
-
var CrossOriginTextureLoader = class extends
|
|
1048
|
+
var CrossOriginTextureLoader = class extends THREE5__namespace.TextureLoader {
|
|
942
1049
|
constructor() {
|
|
943
1050
|
super();
|
|
944
1051
|
this.crossOrigin = "anonymous";
|
|
@@ -956,7 +1063,7 @@ function useBillboardTexture(url) {
|
|
|
956
1063
|
url,
|
|
957
1064
|
(texture) => {
|
|
958
1065
|
if (!active) return;
|
|
959
|
-
texture.colorSpace =
|
|
1066
|
+
texture.colorSpace = THREE5__namespace.SRGBColorSpace;
|
|
960
1067
|
setState({ texture, error: false });
|
|
961
1068
|
},
|
|
962
1069
|
void 0,
|
|
@@ -1009,7 +1116,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
1009
1116
|
}, [texture, frame, node.height, node.width, anchor, cellSize]);
|
|
1010
1117
|
const groundGeometry = React3__default.default.useMemo(() => {
|
|
1011
1118
|
if (anchor !== "top-left" || !texture || !atlasReady) return null;
|
|
1012
|
-
const g = new
|
|
1119
|
+
const g = new THREE5__namespace.PlaneGeometry(size.width, size.height);
|
|
1013
1120
|
g.rotateX(-Math.PI / 2);
|
|
1014
1121
|
return g;
|
|
1015
1122
|
}, [anchor, texture, atlasReady, size.width, size.height]);
|
|
@@ -1017,15 +1124,15 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
1017
1124
|
if (anchor === "top-left") {
|
|
1018
1125
|
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [world[0] + size.width / 2, 0.02, world[2] + size.height / 2], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], children: [
|
|
1019
1126
|
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
1020
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side:
|
|
1127
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE5__namespace.DoubleSide })
|
|
1021
1128
|
] }) });
|
|
1022
1129
|
}
|
|
1023
1130
|
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [world[0], world[1] + size.height / 2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { children: [
|
|
1024
1131
|
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
1025
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side:
|
|
1132
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE5__namespace.DoubleSide })
|
|
1026
1133
|
] }) });
|
|
1027
1134
|
}
|
|
1028
|
-
texture.magFilter = texture.minFilter =
|
|
1135
|
+
texture.magFilter = texture.minFilter = THREE5__namespace.NearestFilter;
|
|
1029
1136
|
texture.needsUpdate = true;
|
|
1030
1137
|
if (frame) {
|
|
1031
1138
|
texture.repeat.set(frame.w / size.imgW, frame.h / size.imgH);
|
|
@@ -1038,7 +1145,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
1038
1145
|
map: texture,
|
|
1039
1146
|
transparent: true,
|
|
1040
1147
|
alphaTest: 0.1,
|
|
1041
|
-
side:
|
|
1148
|
+
side: THREE5__namespace.DoubleSide,
|
|
1042
1149
|
opacity: (node.opacity ?? 1) * groupOpacity
|
|
1043
1150
|
}
|
|
1044
1151
|
) }) });
|
|
@@ -1051,7 +1158,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
1051
1158
|
map: texture,
|
|
1052
1159
|
transparent: true,
|
|
1053
1160
|
alphaTest: 0.1,
|
|
1054
|
-
side:
|
|
1161
|
+
side: THREE5__namespace.DoubleSide,
|
|
1055
1162
|
opacity: node.opacity ?? 1
|
|
1056
1163
|
}
|
|
1057
1164
|
)
|
|
@@ -1120,7 +1227,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1120
1227
|
}
|
|
1121
1228
|
case "poly": {
|
|
1122
1229
|
if (!node.points || node.points.length === 0) return null;
|
|
1123
|
-
const s = new
|
|
1230
|
+
const s = new THREE5__namespace.Shape();
|
|
1124
1231
|
node.points.forEach((p, i) => {
|
|
1125
1232
|
if (i === 0) s.moveTo(p.x, p.y);
|
|
1126
1233
|
else s.lineTo(p.x, p.y);
|
|
@@ -1138,7 +1245,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1138
1245
|
}
|
|
1139
1246
|
return /* @__PURE__ */ jsxRuntime.jsx("group", { ref: groupRef, position: [world[0], world[1] + 0.02, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], children: [
|
|
1140
1247
|
geometry,
|
|
1141
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side:
|
|
1248
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE5__namespace.DoubleSide })
|
|
1142
1249
|
] }) });
|
|
1143
1250
|
}
|
|
1144
1251
|
function Text3D({ node, projector, groupOpacity = 1 }) {
|
|
@@ -1159,64 +1266,66 @@ function Text3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1159
1266
|
}
|
|
1160
1267
|
) });
|
|
1161
1268
|
}
|
|
1162
|
-
var
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1269
|
+
var GROUND_ROTATION = [-Math.PI / 2, 0, 0];
|
|
1270
|
+
var textureCache = /* @__PURE__ */ new Map();
|
|
1271
|
+
function getMeshTexture(url) {
|
|
1272
|
+
const cached = textureCache.get(url);
|
|
1273
|
+
if (cached) return cached;
|
|
1274
|
+
const texture = new THREE5__namespace.TextureLoader().load(url);
|
|
1275
|
+
texture.flipY = false;
|
|
1276
|
+
texture.colorSpace = THREE5__namespace.SRGBColorSpace;
|
|
1277
|
+
texture.wrapS = THREE5__namespace.RepeatWrapping;
|
|
1278
|
+
texture.wrapT = THREE5__namespace.RepeatWrapping;
|
|
1279
|
+
textureCache.set(url, texture);
|
|
1280
|
+
return texture;
|
|
1166
1281
|
}
|
|
1167
|
-
function
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
];
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
let
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
if (f.at <= t) prev = f;
|
|
1195
|
-
else if (!next) next = f;
|
|
1282
|
+
function polyhedronGeometry(node, cellSize) {
|
|
1283
|
+
const verts = node.vertices;
|
|
1284
|
+
const faces = node.faces;
|
|
1285
|
+
const bounds = polyhedronBounds(verts);
|
|
1286
|
+
if (!verts || !bounds || !faces || faces.length === 0) return null;
|
|
1287
|
+
const positions = new Float32Array(verts.length * 3);
|
|
1288
|
+
for (let i = 0; i < verts.length; i++) {
|
|
1289
|
+
positions[i * 3] = verts[i][0] * cellSize;
|
|
1290
|
+
positions[i * 3 + 1] = verts[i][2] * cellSize;
|
|
1291
|
+
positions[i * 3 + 2] = verts[i][1] * cellSize;
|
|
1292
|
+
}
|
|
1293
|
+
const index = [];
|
|
1294
|
+
for (const face of faces) {
|
|
1295
|
+
if (face.length < 3) continue;
|
|
1296
|
+
const [a, b, c] = face;
|
|
1297
|
+
if (a === b || b === c || a === c) continue;
|
|
1298
|
+
if (![a, b, c].every((i) => Number.isInteger(i) && i >= 0 && i < verts.length)) continue;
|
|
1299
|
+
index.push(a, c, b);
|
|
1300
|
+
}
|
|
1301
|
+
if (index.length === 0) return null;
|
|
1302
|
+
const geometry = new THREE5__namespace.BufferGeometry();
|
|
1303
|
+
geometry.setAttribute("position", new THREE5__namespace.BufferAttribute(positions, 3));
|
|
1304
|
+
if (node.uvs && node.uvs.length === verts.length) {
|
|
1305
|
+
const uv = new Float32Array(verts.length * 2);
|
|
1306
|
+
for (let i = 0; i < verts.length; i++) {
|
|
1307
|
+
uv[i * 2] = node.uvs[i][0];
|
|
1308
|
+
uv[i * 2 + 1] = node.uvs[i][1];
|
|
1196
1309
|
}
|
|
1197
|
-
|
|
1198
|
-
if (!next) return prev[key];
|
|
1199
|
-
const span = next.at - prev.at;
|
|
1200
|
-
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
1201
|
-
const a = prev[key];
|
|
1202
|
-
const b = next[key];
|
|
1203
|
-
if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
|
|
1204
|
-
return a;
|
|
1205
|
-
};
|
|
1206
|
-
const num = {};
|
|
1207
|
-
for (const key of NUMERIC_TRACKS2) {
|
|
1208
|
-
const v = trackValue(key);
|
|
1209
|
-
if (v !== void 0) num[key] = v;
|
|
1310
|
+
geometry.setAttribute("uv", new THREE5__namespace.BufferAttribute(uv, 2));
|
|
1210
1311
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1312
|
+
geometry.setIndex(index);
|
|
1313
|
+
geometry.computeVertexNormals();
|
|
1314
|
+
const skin = node.skin;
|
|
1315
|
+
if (skin && skin.indices.length === verts.length && skin.weights.length === verts.length) {
|
|
1316
|
+
const skinIndex = new Uint16Array(verts.length * 4);
|
|
1317
|
+
const skinWeight = new Float32Array(verts.length * 4);
|
|
1318
|
+
for (let i = 0; i < verts.length; i++) {
|
|
1319
|
+
for (let k = 0; k < 4; k++) {
|
|
1320
|
+
skinIndex[i * 4 + k] = skin.indices[i][k] ?? 0;
|
|
1321
|
+
skinWeight[i * 4 + k] = skin.weights[i][k] ?? 0;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
geometry.setAttribute("skinIndex", new THREE5__namespace.BufferAttribute(skinIndex, 4));
|
|
1325
|
+
geometry.setAttribute("skinWeight", new THREE5__namespace.BufferAttribute(skinWeight, 4));
|
|
1326
|
+
}
|
|
1327
|
+
const size = Math.max(bounds.max[0] - bounds.min[0], bounds.max[1] - bounds.min[1], bounds.max[2] - bounds.min[2]) * cellSize;
|
|
1328
|
+
return { geometry, lift: -bounds.min[2] * cellSize, size };
|
|
1220
1329
|
}
|
|
1221
1330
|
function meshGeometry(node, cellSize) {
|
|
1222
1331
|
const seg = clampSegments(node.segments);
|
|
@@ -1244,17 +1353,20 @@ function meshGeometry(node, cellSize) {
|
|
|
1244
1353
|
return { element: /* @__PURE__ */ jsxRuntime.jsx("torusGeometry", { args: [r, tube, Math.max(3, Math.round(seg / 2)), seg] }), lift: r + tube, size: (r + tube) * 2 };
|
|
1245
1354
|
}
|
|
1246
1355
|
case "plane":
|
|
1247
|
-
return { element: /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [w, d] }), lift: 0, size: Math.max(w, d) };
|
|
1356
|
+
return { element: /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [w, d] }), lift: 0, size: Math.max(w, d), baseRotation: GROUND_ROTATION };
|
|
1248
1357
|
case "circle":
|
|
1249
|
-
return { element: /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [r, seg] }), lift: 0, size: r * 2 };
|
|
1358
|
+
return { element: /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [r, seg] }), lift: 0, size: r * 2, baseRotation: GROUND_ROTATION };
|
|
1359
|
+
case "polyhedron":
|
|
1360
|
+
return polyhedronGeometry(node, cellSize);
|
|
1250
1361
|
default:
|
|
1251
1362
|
return null;
|
|
1252
1363
|
}
|
|
1253
1364
|
}
|
|
1365
|
+
var warnedPolyhedronOutline = false;
|
|
1254
1366
|
var SIDE_MAP = {
|
|
1255
|
-
front:
|
|
1256
|
-
back:
|
|
1257
|
-
double:
|
|
1367
|
+
front: THREE5__namespace.FrontSide,
|
|
1368
|
+
back: THREE5__namespace.BackSide,
|
|
1369
|
+
double: THREE5__namespace.DoubleSide
|
|
1258
1370
|
};
|
|
1259
1371
|
function meshMaterial(mat, opacity, ref) {
|
|
1260
1372
|
const m = mat ?? {};
|
|
@@ -1263,7 +1375,8 @@ function meshMaterial(mat, opacity, ref) {
|
|
|
1263
1375
|
color: m.color ?? "#ffffff",
|
|
1264
1376
|
transparent: opacity < 1,
|
|
1265
1377
|
opacity,
|
|
1266
|
-
side: SIDE_MAP[m.side ?? "front"]
|
|
1378
|
+
side: SIDE_MAP[m.side ?? "front"],
|
|
1379
|
+
...m.map ? { map: getMeshTexture(m.map) } : {}
|
|
1267
1380
|
};
|
|
1268
1381
|
const emissive = m.emissive ? { emissive: m.emissive, emissiveIntensity: m.emissiveIntensity ?? 1 } : {};
|
|
1269
1382
|
switch (m.kind ?? "standard") {
|
|
@@ -1298,6 +1411,53 @@ function meshMaterial(mat, opacity, ref) {
|
|
|
1298
1411
|
);
|
|
1299
1412
|
}
|
|
1300
1413
|
}
|
|
1414
|
+
function SkinnedPolyhedron3D({
|
|
1415
|
+
node,
|
|
1416
|
+
skin,
|
|
1417
|
+
geometry,
|
|
1418
|
+
cellSize,
|
|
1419
|
+
opacity
|
|
1420
|
+
}) {
|
|
1421
|
+
const boneStore = React3.useContext(BoneRegistryContext);
|
|
1422
|
+
const meshRef = React3.useRef(null);
|
|
1423
|
+
const [registryTick, setRegistryTick] = React3.useState(0);
|
|
1424
|
+
React3.useEffect(() => boneStore?.subscribe(() => setRegistryTick((t) => t + 1)), [boneStore]);
|
|
1425
|
+
React3.useEffect(() => {
|
|
1426
|
+
const mesh = meshRef.current;
|
|
1427
|
+
if (!mesh || !boneStore) return;
|
|
1428
|
+
const bones = [];
|
|
1429
|
+
for (const name of skin.bones) {
|
|
1430
|
+
const bone = boneStore.get(name);
|
|
1431
|
+
if (!bone) return;
|
|
1432
|
+
bones.push(bone);
|
|
1433
|
+
}
|
|
1434
|
+
if (mesh.skeleton && mesh.skeleton.bones.length === bones.length && mesh.skeleton.bones.every((b, i) => b === bones[i])) return;
|
|
1435
|
+
if (skin.inverseBindMatrices.length !== bones.length) return;
|
|
1436
|
+
const inverses = skin.inverseBindMatrices.map((m) => {
|
|
1437
|
+
const mat = new THREE5__namespace.Matrix4().fromArray(m);
|
|
1438
|
+
mat.elements[12] *= cellSize;
|
|
1439
|
+
mat.elements[13] *= cellSize;
|
|
1440
|
+
mat.elements[14] *= cellSize;
|
|
1441
|
+
return mat;
|
|
1442
|
+
});
|
|
1443
|
+
mesh.bind(new THREE5__namespace.Skeleton(bones, inverses), new THREE5__namespace.Matrix4());
|
|
1444
|
+
}, [registryTick, skin, boneStore, geometry, cellSize]);
|
|
1445
|
+
React3.useEffect(() => {
|
|
1446
|
+
const mesh = meshRef.current;
|
|
1447
|
+
return () => mesh?.skeleton?.dispose();
|
|
1448
|
+
}, []);
|
|
1449
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1450
|
+
"skinnedMesh",
|
|
1451
|
+
{
|
|
1452
|
+
ref: meshRef,
|
|
1453
|
+
geometry,
|
|
1454
|
+
frustumCulled: false,
|
|
1455
|
+
castShadow: node.castShadow ?? true,
|
|
1456
|
+
receiveShadow: node.receiveShadow ?? true,
|
|
1457
|
+
children: meshMaterial(node.material, opacity)
|
|
1458
|
+
}
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1301
1461
|
function Mesh3D({
|
|
1302
1462
|
node,
|
|
1303
1463
|
projector,
|
|
@@ -1310,6 +1470,10 @@ function Mesh3D({
|
|
|
1310
1470
|
const validPos = isValidScenePos(node.position);
|
|
1311
1471
|
const baseWorld = validPos ? projector.toWorld(node.position) : [0, 0, 0];
|
|
1312
1472
|
const geo = React3.useMemo(() => meshGeometry(node, projector.cellSize), [node, projector.cellSize]);
|
|
1473
|
+
React3.useEffect(() => {
|
|
1474
|
+
const g = geo?.geometry;
|
|
1475
|
+
return () => g?.dispose();
|
|
1476
|
+
}, [geo]);
|
|
1313
1477
|
fiber.useFrame(({ clock }) => {
|
|
1314
1478
|
if (!animated || !groupRef.current) return;
|
|
1315
1479
|
const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
|
|
@@ -1322,8 +1486,13 @@ function Mesh3D({
|
|
|
1322
1486
|
);
|
|
1323
1487
|
groupRef.current.scale.setScalar(state.scale);
|
|
1324
1488
|
if (meshRef.current) {
|
|
1489
|
+
const shapeRot = geo?.baseRotation ?? [0, 0, 0];
|
|
1325
1490
|
const base = node.rotation ?? [0, 0, 0];
|
|
1326
|
-
meshRef.current.rotation.set(
|
|
1491
|
+
meshRef.current.rotation.set(
|
|
1492
|
+
shapeRot[0] + base[0] + state.rotate[0],
|
|
1493
|
+
shapeRot[1] + base[1] + state.rotate[1],
|
|
1494
|
+
shapeRot[2] + base[2] + state.rotate[2]
|
|
1495
|
+
);
|
|
1327
1496
|
}
|
|
1328
1497
|
const mat = materialRef.current;
|
|
1329
1498
|
if (mat) {
|
|
@@ -1340,13 +1509,28 @@ function Mesh3D({
|
|
|
1340
1509
|
if (!validPos || !geo) return null;
|
|
1341
1510
|
const lift = (node.pivot ?? "bottom") === "bottom" ? geo.lift : 0;
|
|
1342
1511
|
const opacity = (node.opacity ?? 1) * (node.material?.opacity ?? 1) * groupOpacity;
|
|
1343
|
-
|
|
1512
|
+
if (node.skin && geo.geometry) {
|
|
1513
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: baseWorld, children: /* @__PURE__ */ jsxRuntime.jsx(SkinnedPolyhedron3D, { node, skin: node.skin, geometry: geo.geometry, cellSize: projector.cellSize, opacity }) });
|
|
1514
|
+
}
|
|
1515
|
+
const nodeRotation = node.rotation ?? [0, 0, 0];
|
|
1516
|
+
const shapeRotation = geo.baseRotation ?? [0, 0, 0];
|
|
1517
|
+
const rotation = [
|
|
1518
|
+
shapeRotation[0] + nodeRotation[0],
|
|
1519
|
+
shapeRotation[1] + nodeRotation[1],
|
|
1520
|
+
shapeRotation[2] + nodeRotation[2]
|
|
1521
|
+
];
|
|
1344
1522
|
const outlineScale = geo.size > 0 ? 1 + (node.outline?.width ?? 0.05) * projector.cellSize / geo.size : 1;
|
|
1523
|
+
if (node.outline && geo.geometry && !warnedPolyhedronOutline) {
|
|
1524
|
+
warnedPolyhedronOutline = true;
|
|
1525
|
+
console.warn('[draw-mesh] outline is not yet supported on shape "polyhedron" \u2014 skipped');
|
|
1526
|
+
}
|
|
1527
|
+
const geometryProp = geo.geometry ? { geometry: geo.geometry } : {};
|
|
1345
1528
|
return /* @__PURE__ */ jsxRuntime.jsxs("group", { ref: groupRef, position: baseWorld, children: [
|
|
1346
1529
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1347
1530
|
"mesh",
|
|
1348
1531
|
{
|
|
1349
1532
|
ref: meshRef,
|
|
1533
|
+
...geometryProp,
|
|
1350
1534
|
position: [0, lift, 0],
|
|
1351
1535
|
rotation,
|
|
1352
1536
|
castShadow: node.castShadow ?? true,
|
|
@@ -1357,13 +1541,13 @@ function Mesh3D({
|
|
|
1357
1541
|
]
|
|
1358
1542
|
}
|
|
1359
1543
|
),
|
|
1360
|
-
node.outline && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, lift, 0], rotation, scale: outlineScale, children: [
|
|
1544
|
+
node.outline && !geo.geometry && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, lift, 0], rotation, scale: outlineScale, children: [
|
|
1361
1545
|
geo.element,
|
|
1362
1546
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1363
1547
|
"meshBasicMaterial",
|
|
1364
1548
|
{
|
|
1365
1549
|
color: node.outline.color ?? "#101014",
|
|
1366
|
-
side:
|
|
1550
|
+
side: THREE5__namespace.BackSide,
|
|
1367
1551
|
transparent: opacity < 1,
|
|
1368
1552
|
opacity
|
|
1369
1553
|
}
|
|
@@ -1390,14 +1574,53 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1390
1574
|
case "draw-group": {
|
|
1391
1575
|
if (!isValidScenePos(node.position) || !Array.isArray(node.items)) return null;
|
|
1392
1576
|
if (node.clip) warnUnsupported3d("draw-group:clip");
|
|
1393
|
-
|
|
1394
|
-
const inner = create3DProjector({ cellSize: projector.cellSize });
|
|
1395
|
-
const opacity = (node.opacity ?? 1) * groupOpacity;
|
|
1396
|
-
const s = node.scale ?? 1;
|
|
1397
|
-
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: world, rotation: [0, -(node.rotate ?? 0), 0], scale: [s, s, s], children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node: item, projector: inner, groupOpacity: opacity }, i)) });
|
|
1577
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Group3D, { node, projector, groupOpacity });
|
|
1398
1578
|
}
|
|
1399
1579
|
}
|
|
1400
1580
|
}
|
|
1581
|
+
function Group3D({
|
|
1582
|
+
node,
|
|
1583
|
+
projector,
|
|
1584
|
+
groupOpacity
|
|
1585
|
+
}) {
|
|
1586
|
+
const ref = React3.useRef(null);
|
|
1587
|
+
const animated = isAnimatedGroup(node);
|
|
1588
|
+
const world = projector.toWorld(node.position);
|
|
1589
|
+
const inner = create3DProjector({ cellSize: projector.cellSize });
|
|
1590
|
+
const opacity = (node.opacity ?? 1) * groupOpacity;
|
|
1591
|
+
const s = node.scale ?? 1;
|
|
1592
|
+
const baseRotation = node.rotation ?? [0, -(node.rotate ?? 0), 0];
|
|
1593
|
+
const parentStore = React3.useContext(BoneRegistryContext);
|
|
1594
|
+
const scopedStore = React3.useMemo(() => node.skeleton ? new BoneStore() : null, [node.skeleton]);
|
|
1595
|
+
const boneStore = scopedStore ?? parentStore;
|
|
1596
|
+
const boneObject = React3.useMemo(() => node.bone ? new THREE5__namespace.Bone() : null, [node.bone]);
|
|
1597
|
+
React3.useEffect(() => {
|
|
1598
|
+
if (!node.bone || !boneStore || !boneObject) return;
|
|
1599
|
+
return boneStore.register(node.bone, boneObject);
|
|
1600
|
+
}, [node.bone, boneStore, boneObject]);
|
|
1601
|
+
fiber.useFrame(({ clock }) => {
|
|
1602
|
+
if (!animated || !ref.current) return;
|
|
1603
|
+
const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
|
|
1604
|
+
if (!state) return;
|
|
1605
|
+
const cell = projector.cellSize;
|
|
1606
|
+
ref.current.position.set(
|
|
1607
|
+
world[0] + state.offset[0] * cell,
|
|
1608
|
+
world[1] + state.offset[2] * cell,
|
|
1609
|
+
world[2] + state.offset[1] * cell
|
|
1610
|
+
);
|
|
1611
|
+
ref.current.rotation.set(
|
|
1612
|
+
baseRotation[0] + state.rotate[0],
|
|
1613
|
+
baseRotation[1] + state.rotate[1],
|
|
1614
|
+
baseRotation[2] + state.rotate[2]
|
|
1615
|
+
);
|
|
1616
|
+
ref.current.scale.setScalar(s * state.scale);
|
|
1617
|
+
});
|
|
1618
|
+
const children = /* @__PURE__ */ jsxRuntime.jsxs("group", { ref, position: world, rotation: baseRotation, scale: [s, s, s], children: [
|
|
1619
|
+
boneObject && /* @__PURE__ */ jsxRuntime.jsx("primitive", { object: boneObject }),
|
|
1620
|
+
node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node: item, projector: inner, groupOpacity: opacity }, i))
|
|
1621
|
+
] });
|
|
1622
|
+
return scopedStore ? /* @__PURE__ */ jsxRuntime.jsx(BoneRegistryContext.Provider, { value: scopedStore, children }) : children;
|
|
1623
|
+
}
|
|
1401
1624
|
|
|
1402
1625
|
// lib/drawable/three/game3dTheme.ts
|
|
1403
1626
|
var GRID_COLORS_3D = {
|
|
@@ -1410,10 +1633,26 @@ function cn(...inputs) {
|
|
|
1410
1633
|
}
|
|
1411
1634
|
var DEFAULT_GRID_CONFIG = {
|
|
1412
1635
|
cellSize: 1};
|
|
1636
|
+
function CameraPose({
|
|
1637
|
+
position,
|
|
1638
|
+
fov,
|
|
1639
|
+
controls
|
|
1640
|
+
}) {
|
|
1641
|
+
const camera = fiber.useThree((s) => s.camera);
|
|
1642
|
+
React3.useEffect(() => {
|
|
1643
|
+
camera.position.set(position[0], position[1], position[2]);
|
|
1644
|
+
if (camera.isPerspectiveCamera) {
|
|
1645
|
+
camera.fov = fov;
|
|
1646
|
+
camera.updateProjectionMatrix();
|
|
1647
|
+
}
|
|
1648
|
+
controls.current?.update();
|
|
1649
|
+
}, [camera, position, fov, controls]);
|
|
1650
|
+
return null;
|
|
1651
|
+
}
|
|
1413
1652
|
function RoomEnvironment3D() {
|
|
1414
1653
|
const { gl, scene } = fiber.useThree(({ gl: gl2, scene: scene2 }) => ({ gl: gl2, scene: scene2 }));
|
|
1415
1654
|
React3.useEffect(() => {
|
|
1416
|
-
const pmremGenerator = new
|
|
1655
|
+
const pmremGenerator = new THREE5__namespace.PMREMGenerator(gl);
|
|
1417
1656
|
const envTexture = pmremGenerator.fromScene(new RoomEnvironment_js.RoomEnvironment(), 0.04).texture;
|
|
1418
1657
|
scene.environment = envTexture;
|
|
1419
1658
|
return () => {
|
|
@@ -1449,6 +1688,7 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1449
1688
|
keyUpMap,
|
|
1450
1689
|
pixelsPerUnit,
|
|
1451
1690
|
fov,
|
|
1691
|
+
azimuth,
|
|
1452
1692
|
lighting,
|
|
1453
1693
|
post,
|
|
1454
1694
|
children,
|
|
@@ -1529,6 +1769,7 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1529
1769
|
}),
|
|
1530
1770
|
[gridBounds, cellSize]
|
|
1531
1771
|
);
|
|
1772
|
+
const boneStore = React3.useMemo(() => new BoneStore(), []);
|
|
1532
1773
|
const drawableProjector = React3.useMemo(
|
|
1533
1774
|
() => create3DProjector({
|
|
1534
1775
|
cellSize: gridConfig.cellSize,
|
|
@@ -1541,7 +1782,7 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1541
1782
|
getCameraPosition: () => {
|
|
1542
1783
|
if (controlsRef.current) {
|
|
1543
1784
|
const pos = controlsRef.current.object.position;
|
|
1544
|
-
return new
|
|
1785
|
+
return new THREE5__namespace.Vector3(pos.x, pos.y, pos.z);
|
|
1545
1786
|
}
|
|
1546
1787
|
return null;
|
|
1547
1788
|
},
|
|
@@ -1581,18 +1822,28 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1581
1822
|
const cz = cameraTarget[2];
|
|
1582
1823
|
const d = size * 1;
|
|
1583
1824
|
const fovDeg = fov ?? 45;
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1825
|
+
const base = (() => {
|
|
1826
|
+
switch (cameraMode) {
|
|
1827
|
+
case "isometric":
|
|
1828
|
+
return { position: [cx + d, d * 0.8, cz + d], fov: fovDeg };
|
|
1829
|
+
case "top-down":
|
|
1830
|
+
return { position: [cx, d * 2, cz + d * 0.35], fov: fovDeg };
|
|
1831
|
+
case "front":
|
|
1832
|
+
return { position: [cx, d * 0.32, cz + d * 1.15], fov: fovDeg };
|
|
1833
|
+
case "follow":
|
|
1834
|
+
return { position: [cx, d * 0.5, cz + d], fov: fovDeg };
|
|
1835
|
+
case "perspective":
|
|
1836
|
+
default:
|
|
1837
|
+
return { position: [cx + d, d, cz + d], fov: fovDeg };
|
|
1838
|
+
}
|
|
1839
|
+
})();
|
|
1840
|
+
if (!azimuth) return base;
|
|
1841
|
+
const ox = base.position[0] - cx;
|
|
1842
|
+
const oz = base.position[2] - cz;
|
|
1843
|
+
const c = Math.cos(azimuth);
|
|
1844
|
+
const s = Math.sin(azimuth);
|
|
1845
|
+
return { position: [cx + ox * c - oz * s, base.position[1], cz + ox * s + oz * c], fov: base.fov };
|
|
1846
|
+
}, [cameraMode, gridBounds, cellSize, cameraTarget, fov, azimuth]);
|
|
1596
1847
|
const followWorld = React3.useMemo(() => {
|
|
1597
1848
|
if (followTarget) return drawableProjector.toWorld(followTarget);
|
|
1598
1849
|
return cameraTarget;
|
|
@@ -1652,6 +1903,8 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1652
1903
|
fiber.Canvas,
|
|
1653
1904
|
{
|
|
1654
1905
|
shadows,
|
|
1906
|
+
flat: lighting?.toneMapping === "none",
|
|
1907
|
+
gl: { preserveDrawingBuffer: true },
|
|
1655
1908
|
camera: {
|
|
1656
1909
|
position: cameraConfig.position,
|
|
1657
1910
|
fov: cameraConfig.fov,
|
|
@@ -1666,6 +1919,7 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1666
1919
|
},
|
|
1667
1920
|
children: [
|
|
1668
1921
|
/* @__PURE__ */ jsxRuntime.jsx(CameraController3D, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
1922
|
+
/* @__PURE__ */ jsxRuntime.jsx(CameraPose, { position: cameraConfig.position, fov: cameraConfig.fov, controls: controlsRef }),
|
|
1669
1923
|
(cameraMode === "follow" || cameraMode === "chase") && /* @__PURE__ */ jsxRuntime.jsx(FollowCamera3D, { target: followWorld, offset: followOffset }),
|
|
1670
1924
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1671
1925
|
Lighting3D,
|
|
@@ -1710,7 +1964,7 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1710
1964
|
fadeStrength: 1
|
|
1711
1965
|
}
|
|
1712
1966
|
),
|
|
1713
|
-
allDrawables.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("group", { children: allDrawables.map((node, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node, projector: drawableProjector }, i)) }),
|
|
1967
|
+
allDrawables.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(BoneRegistryContext.Provider, { value: boneStore, children: /* @__PURE__ */ jsxRuntime.jsx("group", { children: allDrawables.map((node, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node, projector: drawableProjector }, i)) }) }),
|
|
1714
1968
|
(tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1715
1969
|
"mesh",
|
|
1716
1970
|
{
|
|
@@ -1746,7 +2000,7 @@ var Canvas3DHost = React3.forwardRef(
|
|
|
1746
2000
|
dampingFactor: 0.05,
|
|
1747
2001
|
enableZoom: true,
|
|
1748
2002
|
enablePan: true,
|
|
1749
|
-
touches: { ONE:
|
|
2003
|
+
touches: { ONE: THREE5__namespace.TOUCH.ROTATE, TWO: THREE5__namespace.TOUCH.DOLLY_PAN },
|
|
1750
2004
|
minDistance: 2,
|
|
1751
2005
|
maxDistance: 100,
|
|
1752
2006
|
maxPolarAngle: Math.PI / 2 - 0.1
|
|
@@ -1769,15 +2023,15 @@ function Scene3D({ background = "#1a1a2e", fog, children }) {
|
|
|
1769
2023
|
if (initializedRef.current) return;
|
|
1770
2024
|
initializedRef.current = true;
|
|
1771
2025
|
if (background.startsWith("#") || background.startsWith("rgb")) {
|
|
1772
|
-
scene.background = new
|
|
2026
|
+
scene.background = new THREE5__namespace.Color(background);
|
|
1773
2027
|
} else {
|
|
1774
|
-
const loader = new
|
|
2028
|
+
const loader = new THREE5__namespace.TextureLoader();
|
|
1775
2029
|
loader.load(background, (texture) => {
|
|
1776
2030
|
scene.background = texture;
|
|
1777
2031
|
});
|
|
1778
2032
|
}
|
|
1779
2033
|
if (fog) {
|
|
1780
|
-
scene.fog = new
|
|
2034
|
+
scene.fog = new THREE5__namespace.Fog(fog.color, fog.near, fog.far);
|
|
1781
2035
|
}
|
|
1782
2036
|
return () => {
|
|
1783
2037
|
scene.background = null;
|
|
@@ -1800,14 +2054,14 @@ var Camera3D = React3.forwardRef(
|
|
|
1800
2054
|
}, ref) => {
|
|
1801
2055
|
const { camera, set, viewport } = fiber.useThree();
|
|
1802
2056
|
const controlsRef = React3.useRef(null);
|
|
1803
|
-
const initialPosition = React3.useRef(new
|
|
1804
|
-
const initialTarget = React3.useRef(new
|
|
2057
|
+
const initialPosition = React3.useRef(new THREE5__namespace.Vector3(...position));
|
|
2058
|
+
const initialTarget = React3.useRef(new THREE5__namespace.Vector3(...target));
|
|
1805
2059
|
React3.useEffect(() => {
|
|
1806
2060
|
let newCamera;
|
|
1807
2061
|
if (mode === "isometric") {
|
|
1808
2062
|
const aspect = viewport.aspect;
|
|
1809
2063
|
const size = 10 / zoom;
|
|
1810
|
-
newCamera = new
|
|
2064
|
+
newCamera = new THREE5__namespace.OrthographicCamera(
|
|
1811
2065
|
-size * aspect,
|
|
1812
2066
|
size * aspect,
|
|
1813
2067
|
size,
|
|
@@ -1816,7 +2070,7 @@ var Camera3D = React3.forwardRef(
|
|
|
1816
2070
|
1e3
|
|
1817
2071
|
);
|
|
1818
2072
|
} else {
|
|
1819
|
-
newCamera = new
|
|
2073
|
+
newCamera = new THREE5__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
|
|
1820
2074
|
}
|
|
1821
2075
|
newCamera.position.copy(initialPosition.current);
|
|
1822
2076
|
newCamera.lookAt(initialTarget.current.x, initialTarget.current.y, initialTarget.current.z);
|
|
@@ -1857,8 +2111,8 @@ var Camera3D = React3.forwardRef(
|
|
|
1857
2111
|
}
|
|
1858
2112
|
},
|
|
1859
2113
|
getViewBounds: () => {
|
|
1860
|
-
const min = new
|
|
1861
|
-
const max = new
|
|
2114
|
+
const min = new THREE5__namespace.Vector3(-10, -10, -10);
|
|
2115
|
+
const max = new THREE5__namespace.Vector3(10, 10, 10);
|
|
1862
2116
|
return { min, max };
|
|
1863
2117
|
}
|
|
1864
2118
|
}));
|
|
@@ -1900,7 +2154,7 @@ var AssetLoader = class {
|
|
|
1900
2154
|
__publicField(this, "textureCache");
|
|
1901
2155
|
__publicField(this, "loadingPromises");
|
|
1902
2156
|
this.objLoader = new OBJLoader_js.OBJLoader();
|
|
1903
|
-
this.textureLoader = new
|
|
2157
|
+
this.textureLoader = new THREE5__namespace.TextureLoader();
|
|
1904
2158
|
this.modelCache = /* @__PURE__ */ new Map();
|
|
1905
2159
|
this.textureCache = /* @__PURE__ */ new Map();
|
|
1906
2160
|
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
@@ -1974,7 +2228,7 @@ var AssetLoader = class {
|
|
|
1974
2228
|
return this.loadingPromises.get(`texture:${url}`);
|
|
1975
2229
|
}
|
|
1976
2230
|
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
1977
|
-
texture.colorSpace =
|
|
2231
|
+
texture.colorSpace = THREE5__namespace.SRGBColorSpace;
|
|
1978
2232
|
this.textureCache.set(url, texture);
|
|
1979
2233
|
this.loadingPromises.delete(`texture:${url}`);
|
|
1980
2234
|
return texture;
|
|
@@ -2048,7 +2302,7 @@ var AssetLoader = class {
|
|
|
2048
2302
|
});
|
|
2049
2303
|
this.modelCache.forEach((model) => {
|
|
2050
2304
|
model.scene.traverse((child) => {
|
|
2051
|
-
if (child instanceof
|
|
2305
|
+
if (child instanceof THREE5__namespace.Mesh) {
|
|
2052
2306
|
child.geometry.dispose();
|
|
2053
2307
|
if (Array.isArray(child.material)) {
|
|
2054
2308
|
child.material.forEach((m) => m.dispose());
|
|
@@ -2098,21 +2352,21 @@ function useThree5(options = {}) {
|
|
|
2098
2352
|
const [isReady, setIsReady] = React3.useState(false);
|
|
2099
2353
|
const [dimensions, setDimensions] = React3.useState({ width: 0, height: 0 });
|
|
2100
2354
|
const initialCameraPosition = React3.useMemo(
|
|
2101
|
-
() => new
|
|
2355
|
+
() => new THREE5__namespace.Vector3(...opts.cameraPosition),
|
|
2102
2356
|
[]
|
|
2103
2357
|
);
|
|
2104
2358
|
React3.useEffect(() => {
|
|
2105
2359
|
if (!containerRef.current) return;
|
|
2106
2360
|
const container = containerRef.current;
|
|
2107
2361
|
const { clientWidth, clientHeight } = container;
|
|
2108
|
-
const scene = new
|
|
2109
|
-
scene.background = new
|
|
2362
|
+
const scene = new THREE5__namespace.Scene();
|
|
2363
|
+
scene.background = new THREE5__namespace.Color(opts.backgroundColor);
|
|
2110
2364
|
sceneRef.current = scene;
|
|
2111
2365
|
let camera;
|
|
2112
2366
|
const aspect = clientWidth / clientHeight;
|
|
2113
2367
|
if (opts.cameraMode === "isometric") {
|
|
2114
2368
|
const size = 10;
|
|
2115
|
-
camera = new
|
|
2369
|
+
camera = new THREE5__namespace.OrthographicCamera(
|
|
2116
2370
|
-size * aspect,
|
|
2117
2371
|
size * aspect,
|
|
2118
2372
|
size,
|
|
@@ -2121,11 +2375,11 @@ function useThree5(options = {}) {
|
|
|
2121
2375
|
1e3
|
|
2122
2376
|
);
|
|
2123
2377
|
} else {
|
|
2124
|
-
camera = new
|
|
2378
|
+
camera = new THREE5__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
|
|
2125
2379
|
}
|
|
2126
2380
|
camera.position.copy(initialCameraPosition);
|
|
2127
2381
|
cameraRef.current = camera;
|
|
2128
|
-
const renderer = new
|
|
2382
|
+
const renderer = new THREE5__namespace.WebGLRenderer({
|
|
2129
2383
|
antialias: true,
|
|
2130
2384
|
alpha: true,
|
|
2131
2385
|
canvas: canvasRef.current || void 0
|
|
@@ -2133,7 +2387,7 @@ function useThree5(options = {}) {
|
|
|
2133
2387
|
renderer.setSize(clientWidth, clientHeight);
|
|
2134
2388
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
2135
2389
|
renderer.shadowMap.enabled = opts.shadows;
|
|
2136
|
-
renderer.shadowMap.type =
|
|
2390
|
+
renderer.shadowMap.type = THREE5__namespace.PCFSoftShadowMap;
|
|
2137
2391
|
rendererRef.current = renderer;
|
|
2138
2392
|
const controls = new OrbitControls_js.OrbitControls(camera, renderer.domElement);
|
|
2139
2393
|
controls.enableDamping = true;
|
|
@@ -2142,16 +2396,16 @@ function useThree5(options = {}) {
|
|
|
2142
2396
|
controls.maxDistance = 100;
|
|
2143
2397
|
controls.maxPolarAngle = Math.PI / 2 - 0.1;
|
|
2144
2398
|
controlsRef.current = controls;
|
|
2145
|
-
const ambientLight = new
|
|
2399
|
+
const ambientLight = new THREE5__namespace.AmbientLight(16777215, 0.6);
|
|
2146
2400
|
scene.add(ambientLight);
|
|
2147
|
-
const directionalLight = new
|
|
2401
|
+
const directionalLight = new THREE5__namespace.DirectionalLight(16777215, 0.8);
|
|
2148
2402
|
directionalLight.position.set(10, 20, 10);
|
|
2149
2403
|
directionalLight.castShadow = opts.shadows;
|
|
2150
2404
|
directionalLight.shadow.mapSize.width = 2048;
|
|
2151
2405
|
directionalLight.shadow.mapSize.height = 2048;
|
|
2152
2406
|
scene.add(directionalLight);
|
|
2153
2407
|
if (opts.showGrid) {
|
|
2154
|
-
const gridHelper = new
|
|
2408
|
+
const gridHelper = new THREE5__namespace.GridHelper(
|
|
2155
2409
|
opts.gridSize,
|
|
2156
2410
|
opts.gridSize,
|
|
2157
2411
|
4473924,
|
|
@@ -2169,10 +2423,10 @@ function useThree5(options = {}) {
|
|
|
2169
2423
|
const handleResize = () => {
|
|
2170
2424
|
const { clientWidth: width, clientHeight: height } = container;
|
|
2171
2425
|
setDimensions({ width, height });
|
|
2172
|
-
if (camera instanceof
|
|
2426
|
+
if (camera instanceof THREE5__namespace.PerspectiveCamera) {
|
|
2173
2427
|
camera.aspect = width / height;
|
|
2174
2428
|
camera.updateProjectionMatrix();
|
|
2175
|
-
} else if (camera instanceof
|
|
2429
|
+
} else if (camera instanceof THREE5__namespace.OrthographicCamera) {
|
|
2176
2430
|
const aspect2 = width / height;
|
|
2177
2431
|
const size = 10;
|
|
2178
2432
|
camera.left = -size * aspect2;
|
|
@@ -2203,7 +2457,7 @@ function useThree5(options = {}) {
|
|
|
2203
2457
|
let newCamera;
|
|
2204
2458
|
if (opts.cameraMode === "isometric") {
|
|
2205
2459
|
const size = 10;
|
|
2206
|
-
newCamera = new
|
|
2460
|
+
newCamera = new THREE5__namespace.OrthographicCamera(
|
|
2207
2461
|
-size * aspect,
|
|
2208
2462
|
size * aspect,
|
|
2209
2463
|
size,
|
|
@@ -2212,7 +2466,7 @@ function useThree5(options = {}) {
|
|
|
2212
2466
|
1e3
|
|
2213
2467
|
);
|
|
2214
2468
|
} else {
|
|
2215
|
-
newCamera = new
|
|
2469
|
+
newCamera = new THREE5__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
|
|
2216
2470
|
}
|
|
2217
2471
|
newCamera.position.copy(currentPos);
|
|
2218
2472
|
cameraRef.current = newCamera;
|
|
@@ -2542,8 +2796,8 @@ function useSceneGraph() {
|
|
|
2542
2796
|
}
|
|
2543
2797
|
function useRaycaster(options) {
|
|
2544
2798
|
const { camera, canvas, cellSize = 1, offsetX = 0, offsetZ = 0 } = options;
|
|
2545
|
-
const raycaster = React3.useRef(new
|
|
2546
|
-
const mouse = React3.useRef(new
|
|
2799
|
+
const raycaster = React3.useRef(new THREE5__namespace.Raycaster());
|
|
2800
|
+
const mouse = React3.useRef(new THREE5__namespace.Vector2());
|
|
2547
2801
|
const clientToNDC = React3.useCallback(
|
|
2548
2802
|
(clientX, clientY) => {
|
|
2549
2803
|
if (!canvas) {
|
|
@@ -2613,8 +2867,8 @@ function useRaycaster(options) {
|
|
|
2613
2867
|
const ndc = clientToNDC(clientX, clientY);
|
|
2614
2868
|
mouse.current.set(ndc.x, ndc.y);
|
|
2615
2869
|
raycaster.current.setFromCamera(mouse.current, camera);
|
|
2616
|
-
const plane = new
|
|
2617
|
-
const target = new
|
|
2870
|
+
const plane = new THREE5__namespace.Plane(new THREE5__namespace.Vector3(0, 1, 0), 0);
|
|
2871
|
+
const target = new THREE5__namespace.Vector3();
|
|
2618
2872
|
const intersection = raycaster.current.ray.intersectPlane(plane, target);
|
|
2619
2873
|
if (intersection) {
|
|
2620
2874
|
const gridX = Math.round((target.x - offsetX) / cellSize);
|
|
@@ -2652,7 +2906,7 @@ function useRaycaster(options) {
|
|
|
2652
2906
|
return {
|
|
2653
2907
|
gridX: gridCoords.x,
|
|
2654
2908
|
gridZ: gridCoords.z,
|
|
2655
|
-
worldPosition: new
|
|
2909
|
+
worldPosition: new THREE5__namespace.Vector3(
|
|
2656
2910
|
gridCoords.x * cellSize + offsetX,
|
|
2657
2911
|
0,
|
|
2658
2912
|
gridCoords.z * cellSize + offsetZ
|
|
@@ -2682,7 +2936,7 @@ var DEFAULT_CONFIG = {
|
|
|
2682
2936
|
};
|
|
2683
2937
|
function gridToWorld(gridX, gridZ, config = DEFAULT_CONFIG) {
|
|
2684
2938
|
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
2685
|
-
return new
|
|
2939
|
+
return new THREE5__namespace.Vector3(
|
|
2686
2940
|
gridX * opts.cellSize + opts.offsetX,
|
|
2687
2941
|
opts.elevation,
|
|
2688
2942
|
gridZ * opts.cellSize + opts.offsetZ
|
|
@@ -2696,17 +2950,17 @@ function worldToGrid(worldX, worldZ, config = DEFAULT_CONFIG) {
|
|
|
2696
2950
|
};
|
|
2697
2951
|
}
|
|
2698
2952
|
function raycastToPlane(camera, mouseX, mouseY, planeY = 0) {
|
|
2699
|
-
const raycaster = new
|
|
2700
|
-
const mouse = new
|
|
2953
|
+
const raycaster = new THREE5__namespace.Raycaster();
|
|
2954
|
+
const mouse = new THREE5__namespace.Vector2(mouseX, mouseY);
|
|
2701
2955
|
raycaster.setFromCamera(mouse, camera);
|
|
2702
|
-
const plane = new
|
|
2703
|
-
const target = new
|
|
2956
|
+
const plane = new THREE5__namespace.Plane(new THREE5__namespace.Vector3(0, 1, 0), -planeY);
|
|
2957
|
+
const target = new THREE5__namespace.Vector3();
|
|
2704
2958
|
const intersection = raycaster.ray.intersectPlane(plane, target);
|
|
2705
2959
|
return intersection ? target : null;
|
|
2706
2960
|
}
|
|
2707
2961
|
function raycastToObjects(camera, mouseX, mouseY, objects) {
|
|
2708
|
-
const raycaster = new
|
|
2709
|
-
const mouse = new
|
|
2962
|
+
const raycaster = new THREE5__namespace.Raycaster();
|
|
2963
|
+
const mouse = new THREE5__namespace.Vector2(mouseX, mouseY);
|
|
2710
2964
|
raycaster.setFromCamera(mouse, camera);
|
|
2711
2965
|
const intersects = raycaster.intersectObjects(objects, true);
|
|
2712
2966
|
return intersects.length > 0 ? intersects[0] : null;
|
|
@@ -2758,14 +3012,14 @@ function getCellsInRadius(centerX, centerZ, radius) {
|
|
|
2758
3012
|
return cells;
|
|
2759
3013
|
}
|
|
2760
3014
|
function createGridHighlight(color = 16776960, opacity = 0.3) {
|
|
2761
|
-
const geometry = new
|
|
2762
|
-
const material = new
|
|
3015
|
+
const geometry = new THREE5__namespace.PlaneGeometry(0.95, 0.95);
|
|
3016
|
+
const material = new THREE5__namespace.MeshBasicMaterial({
|
|
2763
3017
|
color,
|
|
2764
3018
|
transparent: true,
|
|
2765
3019
|
opacity,
|
|
2766
|
-
side:
|
|
3020
|
+
side: THREE5__namespace.DoubleSide
|
|
2767
3021
|
});
|
|
2768
|
-
const mesh = new
|
|
3022
|
+
const mesh = new THREE5__namespace.Mesh(geometry, material);
|
|
2769
3023
|
mesh.rotation.x = -Math.PI / 2;
|
|
2770
3024
|
mesh.position.y = 0.01;
|
|
2771
3025
|
return mesh;
|
|
@@ -2778,31 +3032,31 @@ function normalizeMouseCoordinates(clientX, clientY, element) {
|
|
|
2778
3032
|
};
|
|
2779
3033
|
}
|
|
2780
3034
|
function isInFrustum(position, camera, padding = 0) {
|
|
2781
|
-
const frustum = new
|
|
2782
|
-
const projScreenMatrix = new
|
|
3035
|
+
const frustum = new THREE5__namespace.Frustum();
|
|
3036
|
+
const projScreenMatrix = new THREE5__namespace.Matrix4();
|
|
2783
3037
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2784
3038
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2785
|
-
const sphere = new
|
|
3039
|
+
const sphere = new THREE5__namespace.Sphere(position, padding);
|
|
2786
3040
|
return frustum.intersectsSphere(sphere);
|
|
2787
3041
|
}
|
|
2788
3042
|
function filterByFrustum(positions, camera, padding = 0) {
|
|
2789
|
-
const frustum = new
|
|
2790
|
-
const projScreenMatrix = new
|
|
3043
|
+
const frustum = new THREE5__namespace.Frustum();
|
|
3044
|
+
const projScreenMatrix = new THREE5__namespace.Matrix4();
|
|
2791
3045
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2792
3046
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2793
3047
|
return positions.filter((position) => {
|
|
2794
|
-
const sphere = new
|
|
3048
|
+
const sphere = new THREE5__namespace.Sphere(position, padding);
|
|
2795
3049
|
return frustum.intersectsSphere(sphere);
|
|
2796
3050
|
});
|
|
2797
3051
|
}
|
|
2798
3052
|
function getVisibleIndices(positions, camera, padding = 0) {
|
|
2799
|
-
const frustum = new
|
|
2800
|
-
const projScreenMatrix = new
|
|
3053
|
+
const frustum = new THREE5__namespace.Frustum();
|
|
3054
|
+
const projScreenMatrix = new THREE5__namespace.Matrix4();
|
|
2801
3055
|
const visible = /* @__PURE__ */ new Set();
|
|
2802
3056
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2803
3057
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2804
3058
|
positions.forEach((position, index) => {
|
|
2805
|
-
const sphere = new
|
|
3059
|
+
const sphere = new THREE5__namespace.Sphere(position, padding);
|
|
2806
3060
|
if (frustum.intersectsSphere(sphere)) {
|
|
2807
3061
|
visible.add(index);
|
|
2808
3062
|
}
|
|
@@ -2826,7 +3080,7 @@ function updateInstanceLOD(instancedMesh, positions, camera, lodDistances) {
|
|
|
2826
3080
|
return lodIndices;
|
|
2827
3081
|
}
|
|
2828
3082
|
function cullInstancedMesh(instancedMesh, positions, visibleIndices) {
|
|
2829
|
-
const dummy = new
|
|
3083
|
+
const dummy = new THREE5__namespace.Object3D();
|
|
2830
3084
|
let visibleCount = 0;
|
|
2831
3085
|
positions.forEach((position, index) => {
|
|
2832
3086
|
if (visibleIndices.has(index)) {
|
|
@@ -3993,25 +4247,25 @@ function orbitRingPositions(count, radius, tilt) {
|
|
|
3993
4247
|
return positions;
|
|
3994
4248
|
}
|
|
3995
4249
|
function arcCurve3D(from, to, offset) {
|
|
3996
|
-
const start = new
|
|
3997
|
-
const end = new
|
|
3998
|
-
const mid = new
|
|
3999
|
-
const dir = new
|
|
4000
|
-
const up = new
|
|
4001
|
-
const perp = new
|
|
4250
|
+
const start = new THREE5.Vector3(...from);
|
|
4251
|
+
const end = new THREE5.Vector3(...to);
|
|
4252
|
+
const mid = new THREE5.Vector3().addVectors(start, end).multiplyScalar(0.5);
|
|
4253
|
+
const dir = new THREE5.Vector3().subVectors(end, start).normalize();
|
|
4254
|
+
const up = new THREE5.Vector3(0, 1, 0);
|
|
4255
|
+
const perp = new THREE5.Vector3().crossVectors(dir, up).normalize();
|
|
4002
4256
|
if (perp.length() < 1e-3) {
|
|
4003
|
-
perp.crossVectors(dir, new
|
|
4257
|
+
perp.crossVectors(dir, new THREE5.Vector3(1, 0, 0)).normalize();
|
|
4004
4258
|
}
|
|
4005
4259
|
const control = mid.clone().add(perp.multiplyScalar(offset));
|
|
4006
4260
|
control.y += Math.abs(offset) * 0.3;
|
|
4007
|
-
return new
|
|
4261
|
+
return new THREE5.QuadraticBezierCurve3(start, control, end);
|
|
4008
4262
|
}
|
|
4009
4263
|
function selfLoopCurve3D(position, loopRadius) {
|
|
4010
|
-
const base = new
|
|
4011
|
-
const start = base.clone().add(new
|
|
4012
|
-
const end = base.clone().add(new
|
|
4013
|
-
const control = base.clone().add(new
|
|
4014
|
-
return new
|
|
4264
|
+
const base = new THREE5.Vector3(...position);
|
|
4265
|
+
const start = base.clone().add(new THREE5.Vector3(-loopRadius * 0.3, 0, 0));
|
|
4266
|
+
const end = base.clone().add(new THREE5.Vector3(loopRadius * 0.3, 0, 0));
|
|
4267
|
+
const control = base.clone().add(new THREE5.Vector3(0, loopRadius, 0));
|
|
4268
|
+
return new THREE5.QuadraticBezierCurve3(start, control, end);
|
|
4015
4269
|
}
|
|
4016
4270
|
function treeLayout3D(node, origin, horizontalSpacing, verticalSpacing = 2) {
|
|
4017
4271
|
const results = [];
|
|
@@ -4178,7 +4432,7 @@ var Avl3DOrbitalNode = ({
|
|
|
4178
4432
|
if (!groupRef.current) return;
|
|
4179
4433
|
groupRef.current.rotation.y += delta * (hovered ? 0.4 : 0.2);
|
|
4180
4434
|
groupRef.current.rotation.x += delta * 0.05;
|
|
4181
|
-
currentScale.current =
|
|
4435
|
+
currentScale.current = THREE5.MathUtils.damp(currentScale.current, targetScale, 6, delta);
|
|
4182
4436
|
});
|
|
4183
4437
|
const baseBrightness = 0.3 + Math.min(pageCount, 5) * 0.05;
|
|
4184
4438
|
const emissiveIntensity = hovered ? 0.8 : baseBrightness;
|
|
@@ -4820,7 +5074,7 @@ var Avl3DStateNode = ({
|
|
|
4820
5074
|
const targetScale = hovered ? 1.08 : 1;
|
|
4821
5075
|
const currentScale = React3.useRef(1);
|
|
4822
5076
|
fiber.useFrame((_, delta) => {
|
|
4823
|
-
currentScale.current =
|
|
5077
|
+
currentScale.current = THREE5.MathUtils.damp(currentScale.current, targetScale, 6, delta);
|
|
4824
5078
|
});
|
|
4825
5079
|
const scale = currentScale.current;
|
|
4826
5080
|
return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
|
|
@@ -5000,9 +5254,9 @@ var Avl3DTransitionArc = ({
|
|
|
5000
5254
|
const guardPt = curve.getPoint(0.3);
|
|
5001
5255
|
const arrowPt = curve.getPoint(0.9);
|
|
5002
5256
|
const arrowTangent = curve.getTangent(0.9);
|
|
5003
|
-
const upVec = new
|
|
5004
|
-
const tangentVec = new
|
|
5005
|
-
const quat = new
|
|
5257
|
+
const upVec = new THREE5.Vector3(0, 1, 0);
|
|
5258
|
+
const tangentVec = new THREE5.Vector3(arrowTangent.x, arrowTangent.y, arrowTangent.z).normalize();
|
|
5259
|
+
const quat = new THREE5.Quaternion().setFromUnitVectors(upVec, tangentVec);
|
|
5006
5260
|
const effectPositions2 = [];
|
|
5007
5261
|
for (let ei = 0; ei < 4; ei++) {
|
|
5008
5262
|
const t = 0.7 + ei * 0.05;
|
|
@@ -5226,14 +5480,14 @@ function operatorColor(label) {
|
|
|
5226
5480
|
return "#4A90D9";
|
|
5227
5481
|
}
|
|
5228
5482
|
function edgeGeometry(parent, child) {
|
|
5229
|
-
const p = new
|
|
5230
|
-
const c = new
|
|
5231
|
-
const mid = new
|
|
5232
|
-
const dir = new
|
|
5483
|
+
const p = new THREE5.Vector3(parent.x, parent.y, parent.z);
|
|
5484
|
+
const c = new THREE5.Vector3(child.x, child.y, child.z);
|
|
5485
|
+
const mid = new THREE5.Vector3().addVectors(p, c).multiplyScalar(0.5);
|
|
5486
|
+
const dir = new THREE5.Vector3().subVectors(c, p);
|
|
5233
5487
|
const length = dir.length();
|
|
5234
|
-
const yAxis = new
|
|
5488
|
+
const yAxis = new THREE5.Vector3(0, 1, 0);
|
|
5235
5489
|
const angle = yAxis.angleTo(dir.normalize());
|
|
5236
|
-
const axis = new
|
|
5490
|
+
const axis = new THREE5.Vector3().crossVectors(yAxis, dir).normalize();
|
|
5237
5491
|
if (axis.length() < 1e-3) {
|
|
5238
5492
|
return {
|
|
5239
5493
|
position: [mid.x, mid.y, mid.z],
|
|
@@ -5609,12 +5863,12 @@ function useAvl3DConfig() {
|
|
|
5609
5863
|
}
|
|
5610
5864
|
function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
5611
5865
|
const { camera } = fiber.useThree();
|
|
5612
|
-
const targetPosVec = React3.useRef(new
|
|
5613
|
-
const targetLookVec = React3.useRef(new
|
|
5866
|
+
const targetPosVec = React3.useRef(new THREE5__namespace.Vector3(...targetPosition));
|
|
5867
|
+
const targetLookVec = React3.useRef(new THREE5__namespace.Vector3(...targetLookAt));
|
|
5614
5868
|
const isAnimating = React3.useRef(false);
|
|
5615
5869
|
React3.useEffect(() => {
|
|
5616
|
-
const newTarget = new
|
|
5617
|
-
const newLookAt = new
|
|
5870
|
+
const newTarget = new THREE5__namespace.Vector3(...targetPosition);
|
|
5871
|
+
const newLookAt = new THREE5__namespace.Vector3(...targetLookAt);
|
|
5618
5872
|
if (!newTarget.equals(targetPosVec.current) || !newLookAt.equals(targetLookVec.current)) {
|
|
5619
5873
|
targetPosVec.current.copy(newTarget);
|
|
5620
5874
|
targetLookVec.current.copy(newLookAt);
|
|
@@ -5629,9 +5883,9 @@ function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
|
5629
5883
|
fiber.useFrame((_, delta) => {
|
|
5630
5884
|
if (!isAnimating.current) return;
|
|
5631
5885
|
const speed = 3;
|
|
5632
|
-
camera.position.x =
|
|
5633
|
-
camera.position.y =
|
|
5634
|
-
camera.position.z =
|
|
5886
|
+
camera.position.x = THREE5__namespace.MathUtils.damp(camera.position.x, targetPosVec.current.x, speed, delta);
|
|
5887
|
+
camera.position.y = THREE5__namespace.MathUtils.damp(camera.position.y, targetPosVec.current.y, speed, delta);
|
|
5888
|
+
camera.position.z = THREE5__namespace.MathUtils.damp(camera.position.z, targetPosVec.current.z, speed, delta);
|
|
5635
5889
|
camera.lookAt(targetLookVec.current);
|
|
5636
5890
|
const dist = camera.position.distanceTo(targetPosVec.current);
|
|
5637
5891
|
if (dist < 0.05) {
|
|
@@ -5646,7 +5900,7 @@ function SceneFade({ animating, children }) {
|
|
|
5646
5900
|
fiber.useFrame((_, delta) => {
|
|
5647
5901
|
if (!groupRef.current) return;
|
|
5648
5902
|
const target = animating ? 0 : 1;
|
|
5649
|
-
opacityRef.current =
|
|
5903
|
+
opacityRef.current = THREE5__namespace.MathUtils.damp(opacityRef.current, target, 5, delta);
|
|
5650
5904
|
groupRef.current.visible = opacityRef.current > 0.05;
|
|
5651
5905
|
const s = 0.9 + opacityRef.current * 0.1;
|
|
5652
5906
|
groupRef.current.scale.setScalar(s);
|