@almadar/ui 5.142.0 → 5.143.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.
@@ -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 THREE10 = require('three');
7
+ var THREE11 = 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 THREE10__namespace = /*#__PURE__*/_interopNamespace(THREE10);
42
+ var THREE11__namespace = /*#__PURE__*/_interopNamespace(THREE11);
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 THREE10__namespace.DirectionalLight(directionalColor, directionalIntensity),
534
+ new THREE11__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 THREE10__namespace.Vector3(target[0], target[1], target[2]));
592
- const goal = React3.useRef(new THREE10__namespace.Vector3());
591
+ const look = React3.useRef(new THREE11__namespace.Vector3(target[0], target[1], target[2]));
592
+ const goal = React3.useRef(new THREE11__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 lerp = (a, b, k) => a + (b - a) * k;
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 lerp(a, b, k);
754
+ if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
653
755
  return a;
654
756
  };
655
- for (const key of NUMERIC_TRACKS) {
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: lerp(prevSh.shadow.blur, nextSh.shadow.blur, k) };
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
  }
@@ -816,12 +918,12 @@ function ModelLoader({
816
918
  if (!loadedModel) return null;
817
919
  const cloned = SkeletonUtils.clone(loadedModel);
818
920
  cloned.updateMatrixWorld(true);
819
- const tintColor = tint ? new THREE10__namespace.Color(tint) : null;
921
+ const tintColor = tint ? new THREE11__namespace.Color(tint) : null;
820
922
  cloned.traverse((child) => {
821
- if (child instanceof THREE10__namespace.Mesh) {
923
+ if (child instanceof THREE11__namespace.Mesh) {
822
924
  child.castShadow = castShadow;
823
925
  child.receiveShadow = receiveShadow;
824
- if (tintColor && child.material instanceof THREE10__namespace.MeshStandardMaterial) {
926
+ if (tintColor && child.material instanceof THREE11__namespace.MeshStandardMaterial) {
825
927
  const mat = child.material.clone();
826
928
  mat.color.multiply(tintColor);
827
929
  child.material = mat;
@@ -830,7 +932,7 @@ function ModelLoader({
830
932
  });
831
933
  return cloned;
832
934
  }, [loadedModel, castShadow, receiveShadow, tint]);
833
- const mixer = React3.useMemo(() => model ? new THREE10__namespace.AnimationMixer(model) : null, [model]);
935
+ const mixer = React3.useMemo(() => model ? new THREE11__namespace.AnimationMixer(model) : null, [model]);
834
936
  React3.useEffect(() => {
835
937
  if (!mixer || !animation || clips.length === 0) return;
836
938
  const wanted = animation.toLowerCase();
@@ -847,8 +949,8 @@ function ModelLoader({
847
949
  });
848
950
  const normFactor = React3.useMemo(() => {
849
951
  if (!model) return 1;
850
- const box = new THREE10__namespace.Box3().setFromObject(model);
851
- const size = new THREE10__namespace.Vector3();
952
+ const box = new THREE11__namespace.Box3().setFromObject(model);
953
+ const size = new THREE11__namespace.Vector3();
852
954
  box.getSize(size);
853
955
  const maxDim = Math.max(size.x, size.y, size.z);
854
956
  if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
@@ -938,7 +1040,7 @@ var warnUnsupported3d = (kind) => {
938
1040
  warnedUnsupported.add(kind);
939
1041
  mesh3dLog.warn("unsupported drawable kind on the 3D backend \u2014 skipped", { kind });
940
1042
  };
941
- var CrossOriginTextureLoader = class extends THREE10__namespace.TextureLoader {
1043
+ var CrossOriginTextureLoader = class extends THREE11__namespace.TextureLoader {
942
1044
  constructor() {
943
1045
  super();
944
1046
  this.crossOrigin = "anonymous";
@@ -956,7 +1058,7 @@ function useBillboardTexture(url) {
956
1058
  url,
957
1059
  (texture) => {
958
1060
  if (!active) return;
959
- texture.colorSpace = THREE10__namespace.SRGBColorSpace;
1061
+ texture.colorSpace = THREE11__namespace.SRGBColorSpace;
960
1062
  setState({ texture, error: false });
961
1063
  },
962
1064
  void 0,
@@ -1009,7 +1111,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
1009
1111
  }, [texture, frame, node.height, node.width, anchor, cellSize]);
1010
1112
  const groundGeometry = React3__default.default.useMemo(() => {
1011
1113
  if (anchor !== "top-left" || !texture || !atlasReady) return null;
1012
- const g = new THREE10__namespace.PlaneGeometry(size.width, size.height);
1114
+ const g = new THREE11__namespace.PlaneGeometry(size.width, size.height);
1013
1115
  g.rotateX(-Math.PI / 2);
1014
1116
  return g;
1015
1117
  }, [anchor, texture, atlasReady, size.width, size.height]);
@@ -1017,15 +1119,15 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
1017
1119
  if (anchor === "top-left") {
1018
1120
  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
1121
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
1020
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE10__namespace.DoubleSide })
1122
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE11__namespace.DoubleSide })
1021
1123
  ] }) });
1022
1124
  }
1023
1125
  return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [world[0], world[1] + size.height / 2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { children: [
1024
1126
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
1025
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE10__namespace.DoubleSide })
1127
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE11__namespace.DoubleSide })
1026
1128
  ] }) });
1027
1129
  }
1028
- texture.magFilter = texture.minFilter = THREE10__namespace.NearestFilter;
1130
+ texture.magFilter = texture.minFilter = THREE11__namespace.NearestFilter;
1029
1131
  texture.needsUpdate = true;
1030
1132
  if (frame) {
1031
1133
  texture.repeat.set(frame.w / size.imgW, frame.h / size.imgH);
@@ -1038,7 +1140,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
1038
1140
  map: texture,
1039
1141
  transparent: true,
1040
1142
  alphaTest: 0.1,
1041
- side: THREE10__namespace.DoubleSide,
1143
+ side: THREE11__namespace.DoubleSide,
1042
1144
  opacity: (node.opacity ?? 1) * groupOpacity
1043
1145
  }
1044
1146
  ) }) });
@@ -1051,7 +1153,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
1051
1153
  map: texture,
1052
1154
  transparent: true,
1053
1155
  alphaTest: 0.1,
1054
- side: THREE10__namespace.DoubleSide,
1156
+ side: THREE11__namespace.DoubleSide,
1055
1157
  opacity: node.opacity ?? 1
1056
1158
  }
1057
1159
  )
@@ -1120,7 +1222,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
1120
1222
  }
1121
1223
  case "poly": {
1122
1224
  if (!node.points || node.points.length === 0) return null;
1123
- const s = new THREE10__namespace.Shape();
1225
+ const s = new THREE11__namespace.Shape();
1124
1226
  node.points.forEach((p, i) => {
1125
1227
  if (i === 0) s.moveTo(p.x, p.y);
1126
1228
  else s.lineTo(p.x, p.y);
@@ -1138,7 +1240,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
1138
1240
  }
1139
1241
  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
1242
  geometry,
1141
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE10__namespace.DoubleSide })
1243
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE11__namespace.DoubleSide })
1142
1244
  ] }) });
1143
1245
  }
1144
1246
  function Text3D({ node, projector, groupOpacity = 1 }) {
@@ -1159,64 +1261,46 @@ function Text3D({ node, projector, groupOpacity = 1 }) {
1159
1261
  }
1160
1262
  ) });
1161
1263
  }
1162
- var MESH_SEGMENTS_DEFAULT = 24;
1163
- function clampSegments(segments) {
1164
- const s = segments ?? MESH_SEGMENTS_DEFAULT;
1165
- return Math.min(64, Math.max(3, Math.round(s)));
1166
- }
1167
- function isAnimatedMesh(node) {
1168
- return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
1169
- }
1170
- var lerp2 = (a, b, k) => a + (b - a) * k;
1171
- var NUMERIC_TRACKS2 = [
1172
- "offsetX",
1173
- "offsetY",
1174
- "offsetZ",
1175
- "rotateX",
1176
- "rotateY",
1177
- "rotateZ",
1178
- "scale",
1179
- "opacity",
1180
- "emissiveIntensity"
1181
- ];
1182
- function applyMeshAnimation(node, timeMs) {
1183
- const anim = node.animation;
1184
- if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
1185
- const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
1186
- const cycle = timeMs / anim.durationMs;
1187
- const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
1188
- const trackValue = (key) => {
1189
- const defined = frames.filter((f) => f[key] !== void 0);
1190
- if (defined.length === 0) return void 0;
1191
- let prev;
1192
- let next;
1193
- for (const f of defined) {
1194
- if (f.at <= t) prev = f;
1195
- else if (!next) next = f;
1264
+ var GROUND_ROTATION = [-Math.PI / 2, 0, 0];
1265
+ function polyhedronGeometry(node, cellSize) {
1266
+ const verts = node.vertices;
1267
+ const faces = node.faces;
1268
+ const bounds = polyhedronBounds(verts);
1269
+ if (!verts || !bounds || !faces || faces.length === 0) return null;
1270
+ const positions = new Float32Array(verts.length * 3);
1271
+ for (let i = 0; i < verts.length; i++) {
1272
+ positions[i * 3] = verts[i][0] * cellSize;
1273
+ positions[i * 3 + 1] = verts[i][2] * cellSize;
1274
+ positions[i * 3 + 2] = verts[i][1] * cellSize;
1275
+ }
1276
+ const index = [];
1277
+ for (const face of faces) {
1278
+ if (face.length < 3) continue;
1279
+ const [a, b, c] = face;
1280
+ if (a === b || b === c || a === c) continue;
1281
+ if (![a, b, c].every((i) => Number.isInteger(i) && i >= 0 && i < verts.length)) continue;
1282
+ index.push(a, c, b);
1283
+ }
1284
+ if (index.length === 0) return null;
1285
+ const geometry = new THREE11__namespace.BufferGeometry();
1286
+ geometry.setAttribute("position", new THREE11__namespace.BufferAttribute(positions, 3));
1287
+ geometry.setIndex(index);
1288
+ geometry.computeVertexNormals();
1289
+ const skin = node.skin;
1290
+ if (skin && skin.indices.length === verts.length && skin.weights.length === verts.length) {
1291
+ const skinIndex = new Uint16Array(verts.length * 4);
1292
+ const skinWeight = new Float32Array(verts.length * 4);
1293
+ for (let i = 0; i < verts.length; i++) {
1294
+ for (let k = 0; k < 4; k++) {
1295
+ skinIndex[i * 4 + k] = skin.indices[i][k] ?? 0;
1296
+ skinWeight[i * 4 + k] = skin.weights[i][k] ?? 0;
1297
+ }
1196
1298
  }
1197
- if (!prev) return defined[0][key];
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;
1299
+ geometry.setAttribute("skinIndex", new THREE11__namespace.BufferAttribute(skinIndex, 4));
1300
+ geometry.setAttribute("skinWeight", new THREE11__namespace.BufferAttribute(skinWeight, 4));
1210
1301
  }
1211
- return {
1212
- offset: [num.offsetX ?? 0, num.offsetY ?? 0, num.offsetZ ?? 0],
1213
- rotate: [num.rotateX ?? 0, num.rotateY ?? 0, num.rotateZ ?? 0],
1214
- scale: num.scale ?? 1,
1215
- opacity: num.opacity,
1216
- emissiveIntensity: num.emissiveIntensity,
1217
- color: trackValue("color"),
1218
- emissive: trackValue("emissive")
1219
- };
1302
+ const size = Math.max(bounds.max[0] - bounds.min[0], bounds.max[1] - bounds.min[1], bounds.max[2] - bounds.min[2]) * cellSize;
1303
+ return { geometry, lift: -bounds.min[2] * cellSize, size };
1220
1304
  }
1221
1305
  function meshGeometry(node, cellSize) {
1222
1306
  const seg = clampSegments(node.segments);
@@ -1244,17 +1328,20 @@ function meshGeometry(node, cellSize) {
1244
1328
  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
1329
  }
1246
1330
  case "plane":
1247
- return { element: /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [w, d] }), lift: 0, size: Math.max(w, d) };
1331
+ return { element: /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [w, d] }), lift: 0, size: Math.max(w, d), baseRotation: GROUND_ROTATION };
1248
1332
  case "circle":
1249
- return { element: /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [r, seg] }), lift: 0, size: r * 2 };
1333
+ return { element: /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [r, seg] }), lift: 0, size: r * 2, baseRotation: GROUND_ROTATION };
1334
+ case "polyhedron":
1335
+ return polyhedronGeometry(node, cellSize);
1250
1336
  default:
1251
1337
  return null;
1252
1338
  }
1253
1339
  }
1340
+ var warnedPolyhedronOutline = false;
1254
1341
  var SIDE_MAP = {
1255
- front: THREE10__namespace.FrontSide,
1256
- back: THREE10__namespace.BackSide,
1257
- double: THREE10__namespace.DoubleSide
1342
+ front: THREE11__namespace.FrontSide,
1343
+ back: THREE11__namespace.BackSide,
1344
+ double: THREE11__namespace.DoubleSide
1258
1345
  };
1259
1346
  function meshMaterial(mat, opacity, ref) {
1260
1347
  const m = mat ?? {};
@@ -1298,6 +1385,53 @@ function meshMaterial(mat, opacity, ref) {
1298
1385
  );
1299
1386
  }
1300
1387
  }
1388
+ function SkinnedPolyhedron3D({
1389
+ node,
1390
+ skin,
1391
+ geometry,
1392
+ cellSize,
1393
+ opacity
1394
+ }) {
1395
+ const boneStore = React3.useContext(BoneRegistryContext);
1396
+ const meshRef = React3.useRef(null);
1397
+ const [registryTick, setRegistryTick] = React3.useState(0);
1398
+ React3.useEffect(() => boneStore?.subscribe(() => setRegistryTick((t) => t + 1)), [boneStore]);
1399
+ React3.useEffect(() => {
1400
+ const mesh = meshRef.current;
1401
+ if (!mesh || !boneStore) return;
1402
+ const bones = [];
1403
+ for (const name of skin.bones) {
1404
+ const bone = boneStore.get(name);
1405
+ if (!bone) return;
1406
+ bones.push(bone);
1407
+ }
1408
+ if (mesh.skeleton && mesh.skeleton.bones.length === bones.length && mesh.skeleton.bones.every((b, i) => b === bones[i])) return;
1409
+ if (skin.inverseBindMatrices.length !== bones.length) return;
1410
+ const inverses = skin.inverseBindMatrices.map((m) => {
1411
+ const mat = new THREE11__namespace.Matrix4().fromArray(m);
1412
+ mat.elements[12] *= cellSize;
1413
+ mat.elements[13] *= cellSize;
1414
+ mat.elements[14] *= cellSize;
1415
+ return mat;
1416
+ });
1417
+ mesh.bind(new THREE11__namespace.Skeleton(bones, inverses), new THREE11__namespace.Matrix4());
1418
+ }, [registryTick, skin, boneStore, geometry, cellSize]);
1419
+ React3.useEffect(() => {
1420
+ const mesh = meshRef.current;
1421
+ return () => mesh?.skeleton?.dispose();
1422
+ }, []);
1423
+ return /* @__PURE__ */ jsxRuntime.jsx(
1424
+ "skinnedMesh",
1425
+ {
1426
+ ref: meshRef,
1427
+ geometry,
1428
+ frustumCulled: false,
1429
+ castShadow: node.castShadow ?? true,
1430
+ receiveShadow: node.receiveShadow ?? true,
1431
+ children: meshMaterial(node.material, opacity)
1432
+ }
1433
+ );
1434
+ }
1301
1435
  function Mesh3D({
1302
1436
  node,
1303
1437
  projector,
@@ -1310,6 +1444,10 @@ function Mesh3D({
1310
1444
  const validPos = isValidScenePos(node.position);
1311
1445
  const baseWorld = validPos ? projector.toWorld(node.position) : [0, 0, 0];
1312
1446
  const geo = React3.useMemo(() => meshGeometry(node, projector.cellSize), [node, projector.cellSize]);
1447
+ React3.useEffect(() => {
1448
+ const g = geo?.geometry;
1449
+ return () => g?.dispose();
1450
+ }, [geo]);
1313
1451
  fiber.useFrame(({ clock }) => {
1314
1452
  if (!animated || !groupRef.current) return;
1315
1453
  const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
@@ -1322,8 +1460,13 @@ function Mesh3D({
1322
1460
  );
1323
1461
  groupRef.current.scale.setScalar(state.scale);
1324
1462
  if (meshRef.current) {
1463
+ const shapeRot = geo?.baseRotation ?? [0, 0, 0];
1325
1464
  const base = node.rotation ?? [0, 0, 0];
1326
- meshRef.current.rotation.set(base[0] + state.rotate[0], base[1] + state.rotate[1], base[2] + state.rotate[2]);
1465
+ meshRef.current.rotation.set(
1466
+ shapeRot[0] + base[0] + state.rotate[0],
1467
+ shapeRot[1] + base[1] + state.rotate[1],
1468
+ shapeRot[2] + base[2] + state.rotate[2]
1469
+ );
1327
1470
  }
1328
1471
  const mat = materialRef.current;
1329
1472
  if (mat) {
@@ -1340,13 +1483,28 @@ function Mesh3D({
1340
1483
  if (!validPos || !geo) return null;
1341
1484
  const lift = (node.pivot ?? "bottom") === "bottom" ? geo.lift : 0;
1342
1485
  const opacity = (node.opacity ?? 1) * (node.material?.opacity ?? 1) * groupOpacity;
1343
- const rotation = node.rotation ?? [0, 0, 0];
1486
+ if (node.skin && geo.geometry) {
1487
+ return /* @__PURE__ */ jsxRuntime.jsx("group", { position: baseWorld, children: /* @__PURE__ */ jsxRuntime.jsx(SkinnedPolyhedron3D, { node, skin: node.skin, geometry: geo.geometry, cellSize: projector.cellSize, opacity }) });
1488
+ }
1489
+ const nodeRotation = node.rotation ?? [0, 0, 0];
1490
+ const shapeRotation = geo.baseRotation ?? [0, 0, 0];
1491
+ const rotation = [
1492
+ shapeRotation[0] + nodeRotation[0],
1493
+ shapeRotation[1] + nodeRotation[1],
1494
+ shapeRotation[2] + nodeRotation[2]
1495
+ ];
1344
1496
  const outlineScale = geo.size > 0 ? 1 + (node.outline?.width ?? 0.05) * projector.cellSize / geo.size : 1;
1497
+ if (node.outline && geo.geometry && !warnedPolyhedronOutline) {
1498
+ warnedPolyhedronOutline = true;
1499
+ console.warn('[draw-mesh] outline is not yet supported on shape "polyhedron" \u2014 skipped');
1500
+ }
1501
+ const geometryProp = geo.geometry ? { geometry: geo.geometry } : {};
1345
1502
  return /* @__PURE__ */ jsxRuntime.jsxs("group", { ref: groupRef, position: baseWorld, children: [
1346
1503
  /* @__PURE__ */ jsxRuntime.jsxs(
1347
1504
  "mesh",
1348
1505
  {
1349
1506
  ref: meshRef,
1507
+ ...geometryProp,
1350
1508
  position: [0, lift, 0],
1351
1509
  rotation,
1352
1510
  castShadow: node.castShadow ?? true,
@@ -1357,13 +1515,13 @@ function Mesh3D({
1357
1515
  ]
1358
1516
  }
1359
1517
  ),
1360
- node.outline && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, lift, 0], rotation, scale: outlineScale, children: [
1518
+ node.outline && !geo.geometry && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, lift, 0], rotation, scale: outlineScale, children: [
1361
1519
  geo.element,
1362
1520
  /* @__PURE__ */ jsxRuntime.jsx(
1363
1521
  "meshBasicMaterial",
1364
1522
  {
1365
1523
  color: node.outline.color ?? "#101014",
1366
- side: THREE10__namespace.BackSide,
1524
+ side: THREE11__namespace.BackSide,
1367
1525
  transparent: opacity < 1,
1368
1526
  opacity
1369
1527
  }
@@ -1390,14 +1548,53 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
1390
1548
  case "draw-group": {
1391
1549
  if (!isValidScenePos(node.position) || !Array.isArray(node.items)) return null;
1392
1550
  if (node.clip) warnUnsupported3d("draw-group:clip");
1393
- const world = projector.toWorld(node.position);
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)) });
1551
+ return /* @__PURE__ */ jsxRuntime.jsx(Group3D, { node, projector, groupOpacity });
1398
1552
  }
1399
1553
  }
1400
1554
  }
1555
+ function Group3D({
1556
+ node,
1557
+ projector,
1558
+ groupOpacity
1559
+ }) {
1560
+ const ref = React3.useRef(null);
1561
+ const animated = isAnimatedGroup(node);
1562
+ const world = projector.toWorld(node.position);
1563
+ const inner = create3DProjector({ cellSize: projector.cellSize });
1564
+ const opacity = (node.opacity ?? 1) * groupOpacity;
1565
+ const s = node.scale ?? 1;
1566
+ const baseRotation = node.rotation ?? [0, -(node.rotate ?? 0), 0];
1567
+ const parentStore = React3.useContext(BoneRegistryContext);
1568
+ const scopedStore = React3.useMemo(() => node.skeleton ? new BoneStore() : null, [node.skeleton]);
1569
+ const boneStore = scopedStore ?? parentStore;
1570
+ const boneObject = React3.useMemo(() => node.bone ? new THREE11__namespace.Bone() : null, [node.bone]);
1571
+ React3.useEffect(() => {
1572
+ if (!node.bone || !boneStore || !boneObject) return;
1573
+ return boneStore.register(node.bone, boneObject);
1574
+ }, [node.bone, boneStore, boneObject]);
1575
+ fiber.useFrame(({ clock }) => {
1576
+ if (!animated || !ref.current) return;
1577
+ const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
1578
+ if (!state) return;
1579
+ const cell = projector.cellSize;
1580
+ ref.current.position.set(
1581
+ world[0] + state.offset[0] * cell,
1582
+ world[1] + state.offset[2] * cell,
1583
+ world[2] + state.offset[1] * cell
1584
+ );
1585
+ ref.current.rotation.set(
1586
+ baseRotation[0] + state.rotate[0],
1587
+ baseRotation[1] + state.rotate[1],
1588
+ baseRotation[2] + state.rotate[2]
1589
+ );
1590
+ ref.current.scale.setScalar(s * state.scale);
1591
+ });
1592
+ const children = /* @__PURE__ */ jsxRuntime.jsxs("group", { ref, position: world, rotation: baseRotation, scale: [s, s, s], children: [
1593
+ boneObject && /* @__PURE__ */ jsxRuntime.jsx("primitive", { object: boneObject }),
1594
+ node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node: item, projector: inner, groupOpacity: opacity }, i))
1595
+ ] });
1596
+ return scopedStore ? /* @__PURE__ */ jsxRuntime.jsx(BoneRegistryContext.Provider, { value: scopedStore, children }) : children;
1597
+ }
1401
1598
 
1402
1599
  // lib/drawable/three/game3dTheme.ts
1403
1600
  var GRID_COLORS_3D = {
@@ -1413,7 +1610,7 @@ var DEFAULT_GRID_CONFIG = {
1413
1610
  function RoomEnvironment3D() {
1414
1611
  const { gl, scene } = fiber.useThree(({ gl: gl2, scene: scene2 }) => ({ gl: gl2, scene: scene2 }));
1415
1612
  React3.useEffect(() => {
1416
- const pmremGenerator = new THREE10__namespace.PMREMGenerator(gl);
1613
+ const pmremGenerator = new THREE11__namespace.PMREMGenerator(gl);
1417
1614
  const envTexture = pmremGenerator.fromScene(new RoomEnvironment_js.RoomEnvironment(), 0.04).texture;
1418
1615
  scene.environment = envTexture;
1419
1616
  return () => {
@@ -1529,6 +1726,7 @@ var Canvas3DHost = React3.forwardRef(
1529
1726
  }),
1530
1727
  [gridBounds, cellSize]
1531
1728
  );
1729
+ const boneStore = React3.useMemo(() => new BoneStore(), []);
1532
1730
  const drawableProjector = React3.useMemo(
1533
1731
  () => create3DProjector({
1534
1732
  cellSize: gridConfig.cellSize,
@@ -1541,7 +1739,7 @@ var Canvas3DHost = React3.forwardRef(
1541
1739
  getCameraPosition: () => {
1542
1740
  if (controlsRef.current) {
1543
1741
  const pos = controlsRef.current.object.position;
1544
- return new THREE10__namespace.Vector3(pos.x, pos.y, pos.z);
1742
+ return new THREE11__namespace.Vector3(pos.x, pos.y, pos.z);
1545
1743
  }
1546
1744
  return null;
1547
1745
  },
@@ -1586,6 +1784,8 @@ var Canvas3DHost = React3.forwardRef(
1586
1784
  return { position: [cx + d, d * 0.8, cz + d], fov: fovDeg };
1587
1785
  case "top-down":
1588
1786
  return { position: [cx, d * 2, cz + d * 0.35], fov: fovDeg };
1787
+ case "front":
1788
+ return { position: [cx, d * 0.32, cz + d * 1.15], fov: fovDeg };
1589
1789
  case "follow":
1590
1790
  return { position: [cx, d * 0.5, cz + d], fov: fovDeg };
1591
1791
  case "perspective":
@@ -1652,6 +1852,7 @@ var Canvas3DHost = React3.forwardRef(
1652
1852
  fiber.Canvas,
1653
1853
  {
1654
1854
  shadows,
1855
+ flat: lighting?.toneMapping === "none",
1655
1856
  camera: {
1656
1857
  position: cameraConfig.position,
1657
1858
  fov: cameraConfig.fov,
@@ -1710,7 +1911,7 @@ var Canvas3DHost = React3.forwardRef(
1710
1911
  fadeStrength: 1
1711
1912
  }
1712
1913
  ),
1713
- allDrawables.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("group", { children: allDrawables.map((node, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node, projector: drawableProjector }, i)) }),
1914
+ 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
1915
  (tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxRuntime.jsxs(
1715
1916
  "mesh",
1716
1917
  {
@@ -1746,7 +1947,7 @@ var Canvas3DHost = React3.forwardRef(
1746
1947
  dampingFactor: 0.05,
1747
1948
  enableZoom: true,
1748
1949
  enablePan: true,
1749
- touches: { ONE: THREE10__namespace.TOUCH.ROTATE, TWO: THREE10__namespace.TOUCH.DOLLY_PAN },
1950
+ touches: { ONE: THREE11__namespace.TOUCH.ROTATE, TWO: THREE11__namespace.TOUCH.DOLLY_PAN },
1750
1951
  minDistance: 2,
1751
1952
  maxDistance: 100,
1752
1953
  maxPolarAngle: Math.PI / 2 - 0.1
@@ -1769,15 +1970,15 @@ function Scene3D({ background = "#1a1a2e", fog, children }) {
1769
1970
  if (initializedRef.current) return;
1770
1971
  initializedRef.current = true;
1771
1972
  if (background.startsWith("#") || background.startsWith("rgb")) {
1772
- scene.background = new THREE10__namespace.Color(background);
1973
+ scene.background = new THREE11__namespace.Color(background);
1773
1974
  } else {
1774
- const loader = new THREE10__namespace.TextureLoader();
1975
+ const loader = new THREE11__namespace.TextureLoader();
1775
1976
  loader.load(background, (texture) => {
1776
1977
  scene.background = texture;
1777
1978
  });
1778
1979
  }
1779
1980
  if (fog) {
1780
- scene.fog = new THREE10__namespace.Fog(fog.color, fog.near, fog.far);
1981
+ scene.fog = new THREE11__namespace.Fog(fog.color, fog.near, fog.far);
1781
1982
  }
1782
1983
  return () => {
1783
1984
  scene.background = null;
@@ -1800,14 +2001,14 @@ var Camera3D = React3.forwardRef(
1800
2001
  }, ref) => {
1801
2002
  const { camera, set, viewport } = fiber.useThree();
1802
2003
  const controlsRef = React3.useRef(null);
1803
- const initialPosition = React3.useRef(new THREE10__namespace.Vector3(...position));
1804
- const initialTarget = React3.useRef(new THREE10__namespace.Vector3(...target));
2004
+ const initialPosition = React3.useRef(new THREE11__namespace.Vector3(...position));
2005
+ const initialTarget = React3.useRef(new THREE11__namespace.Vector3(...target));
1805
2006
  React3.useEffect(() => {
1806
2007
  let newCamera;
1807
2008
  if (mode === "isometric") {
1808
2009
  const aspect = viewport.aspect;
1809
2010
  const size = 10 / zoom;
1810
- newCamera = new THREE10__namespace.OrthographicCamera(
2011
+ newCamera = new THREE11__namespace.OrthographicCamera(
1811
2012
  -size * aspect,
1812
2013
  size * aspect,
1813
2014
  size,
@@ -1816,7 +2017,7 @@ var Camera3D = React3.forwardRef(
1816
2017
  1e3
1817
2018
  );
1818
2019
  } else {
1819
- newCamera = new THREE10__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
2020
+ newCamera = new THREE11__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
1820
2021
  }
1821
2022
  newCamera.position.copy(initialPosition.current);
1822
2023
  newCamera.lookAt(initialTarget.current.x, initialTarget.current.y, initialTarget.current.z);
@@ -1857,8 +2058,8 @@ var Camera3D = React3.forwardRef(
1857
2058
  }
1858
2059
  },
1859
2060
  getViewBounds: () => {
1860
- const min = new THREE10__namespace.Vector3(-10, -10, -10);
1861
- const max = new THREE10__namespace.Vector3(10, 10, 10);
2061
+ const min = new THREE11__namespace.Vector3(-10, -10, -10);
2062
+ const max = new THREE11__namespace.Vector3(10, 10, 10);
1862
2063
  return { min, max };
1863
2064
  }
1864
2065
  }));
@@ -1900,7 +2101,7 @@ var AssetLoader = class {
1900
2101
  __publicField(this, "textureCache");
1901
2102
  __publicField(this, "loadingPromises");
1902
2103
  this.objLoader = new OBJLoader_js.OBJLoader();
1903
- this.textureLoader = new THREE10__namespace.TextureLoader();
2104
+ this.textureLoader = new THREE11__namespace.TextureLoader();
1904
2105
  this.modelCache = /* @__PURE__ */ new Map();
1905
2106
  this.textureCache = /* @__PURE__ */ new Map();
1906
2107
  this.loadingPromises = /* @__PURE__ */ new Map();
@@ -1974,7 +2175,7 @@ var AssetLoader = class {
1974
2175
  return this.loadingPromises.get(`texture:${url}`);
1975
2176
  }
1976
2177
  const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
1977
- texture.colorSpace = THREE10__namespace.SRGBColorSpace;
2178
+ texture.colorSpace = THREE11__namespace.SRGBColorSpace;
1978
2179
  this.textureCache.set(url, texture);
1979
2180
  this.loadingPromises.delete(`texture:${url}`);
1980
2181
  return texture;
@@ -2048,7 +2249,7 @@ var AssetLoader = class {
2048
2249
  });
2049
2250
  this.modelCache.forEach((model) => {
2050
2251
  model.scene.traverse((child) => {
2051
- if (child instanceof THREE10__namespace.Mesh) {
2252
+ if (child instanceof THREE11__namespace.Mesh) {
2052
2253
  child.geometry.dispose();
2053
2254
  if (Array.isArray(child.material)) {
2054
2255
  child.material.forEach((m) => m.dispose());
@@ -2098,21 +2299,21 @@ function useThree5(options = {}) {
2098
2299
  const [isReady, setIsReady] = React3.useState(false);
2099
2300
  const [dimensions, setDimensions] = React3.useState({ width: 0, height: 0 });
2100
2301
  const initialCameraPosition = React3.useMemo(
2101
- () => new THREE10__namespace.Vector3(...opts.cameraPosition),
2302
+ () => new THREE11__namespace.Vector3(...opts.cameraPosition),
2102
2303
  []
2103
2304
  );
2104
2305
  React3.useEffect(() => {
2105
2306
  if (!containerRef.current) return;
2106
2307
  const container = containerRef.current;
2107
2308
  const { clientWidth, clientHeight } = container;
2108
- const scene = new THREE10__namespace.Scene();
2109
- scene.background = new THREE10__namespace.Color(opts.backgroundColor);
2309
+ const scene = new THREE11__namespace.Scene();
2310
+ scene.background = new THREE11__namespace.Color(opts.backgroundColor);
2110
2311
  sceneRef.current = scene;
2111
2312
  let camera;
2112
2313
  const aspect = clientWidth / clientHeight;
2113
2314
  if (opts.cameraMode === "isometric") {
2114
2315
  const size = 10;
2115
- camera = new THREE10__namespace.OrthographicCamera(
2316
+ camera = new THREE11__namespace.OrthographicCamera(
2116
2317
  -size * aspect,
2117
2318
  size * aspect,
2118
2319
  size,
@@ -2121,11 +2322,11 @@ function useThree5(options = {}) {
2121
2322
  1e3
2122
2323
  );
2123
2324
  } else {
2124
- camera = new THREE10__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
2325
+ camera = new THREE11__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
2125
2326
  }
2126
2327
  camera.position.copy(initialCameraPosition);
2127
2328
  cameraRef.current = camera;
2128
- const renderer = new THREE10__namespace.WebGLRenderer({
2329
+ const renderer = new THREE11__namespace.WebGLRenderer({
2129
2330
  antialias: true,
2130
2331
  alpha: true,
2131
2332
  canvas: canvasRef.current || void 0
@@ -2133,7 +2334,7 @@ function useThree5(options = {}) {
2133
2334
  renderer.setSize(clientWidth, clientHeight);
2134
2335
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
2135
2336
  renderer.shadowMap.enabled = opts.shadows;
2136
- renderer.shadowMap.type = THREE10__namespace.PCFSoftShadowMap;
2337
+ renderer.shadowMap.type = THREE11__namespace.PCFSoftShadowMap;
2137
2338
  rendererRef.current = renderer;
2138
2339
  const controls = new OrbitControls_js.OrbitControls(camera, renderer.domElement);
2139
2340
  controls.enableDamping = true;
@@ -2142,16 +2343,16 @@ function useThree5(options = {}) {
2142
2343
  controls.maxDistance = 100;
2143
2344
  controls.maxPolarAngle = Math.PI / 2 - 0.1;
2144
2345
  controlsRef.current = controls;
2145
- const ambientLight = new THREE10__namespace.AmbientLight(16777215, 0.6);
2346
+ const ambientLight = new THREE11__namespace.AmbientLight(16777215, 0.6);
2146
2347
  scene.add(ambientLight);
2147
- const directionalLight = new THREE10__namespace.DirectionalLight(16777215, 0.8);
2348
+ const directionalLight = new THREE11__namespace.DirectionalLight(16777215, 0.8);
2148
2349
  directionalLight.position.set(10, 20, 10);
2149
2350
  directionalLight.castShadow = opts.shadows;
2150
2351
  directionalLight.shadow.mapSize.width = 2048;
2151
2352
  directionalLight.shadow.mapSize.height = 2048;
2152
2353
  scene.add(directionalLight);
2153
2354
  if (opts.showGrid) {
2154
- const gridHelper = new THREE10__namespace.GridHelper(
2355
+ const gridHelper = new THREE11__namespace.GridHelper(
2155
2356
  opts.gridSize,
2156
2357
  opts.gridSize,
2157
2358
  4473924,
@@ -2169,10 +2370,10 @@ function useThree5(options = {}) {
2169
2370
  const handleResize = () => {
2170
2371
  const { clientWidth: width, clientHeight: height } = container;
2171
2372
  setDimensions({ width, height });
2172
- if (camera instanceof THREE10__namespace.PerspectiveCamera) {
2373
+ if (camera instanceof THREE11__namespace.PerspectiveCamera) {
2173
2374
  camera.aspect = width / height;
2174
2375
  camera.updateProjectionMatrix();
2175
- } else if (camera instanceof THREE10__namespace.OrthographicCamera) {
2376
+ } else if (camera instanceof THREE11__namespace.OrthographicCamera) {
2176
2377
  const aspect2 = width / height;
2177
2378
  const size = 10;
2178
2379
  camera.left = -size * aspect2;
@@ -2203,7 +2404,7 @@ function useThree5(options = {}) {
2203
2404
  let newCamera;
2204
2405
  if (opts.cameraMode === "isometric") {
2205
2406
  const size = 10;
2206
- newCamera = new THREE10__namespace.OrthographicCamera(
2407
+ newCamera = new THREE11__namespace.OrthographicCamera(
2207
2408
  -size * aspect,
2208
2409
  size * aspect,
2209
2410
  size,
@@ -2212,7 +2413,7 @@ function useThree5(options = {}) {
2212
2413
  1e3
2213
2414
  );
2214
2415
  } else {
2215
- newCamera = new THREE10__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
2416
+ newCamera = new THREE11__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
2216
2417
  }
2217
2418
  newCamera.position.copy(currentPos);
2218
2419
  cameraRef.current = newCamera;
@@ -2542,8 +2743,8 @@ function useSceneGraph() {
2542
2743
  }
2543
2744
  function useRaycaster(options) {
2544
2745
  const { camera, canvas, cellSize = 1, offsetX = 0, offsetZ = 0 } = options;
2545
- const raycaster = React3.useRef(new THREE10__namespace.Raycaster());
2546
- const mouse = React3.useRef(new THREE10__namespace.Vector2());
2746
+ const raycaster = React3.useRef(new THREE11__namespace.Raycaster());
2747
+ const mouse = React3.useRef(new THREE11__namespace.Vector2());
2547
2748
  const clientToNDC = React3.useCallback(
2548
2749
  (clientX, clientY) => {
2549
2750
  if (!canvas) {
@@ -2613,8 +2814,8 @@ function useRaycaster(options) {
2613
2814
  const ndc = clientToNDC(clientX, clientY);
2614
2815
  mouse.current.set(ndc.x, ndc.y);
2615
2816
  raycaster.current.setFromCamera(mouse.current, camera);
2616
- const plane = new THREE10__namespace.Plane(new THREE10__namespace.Vector3(0, 1, 0), 0);
2617
- const target = new THREE10__namespace.Vector3();
2817
+ const plane = new THREE11__namespace.Plane(new THREE11__namespace.Vector3(0, 1, 0), 0);
2818
+ const target = new THREE11__namespace.Vector3();
2618
2819
  const intersection = raycaster.current.ray.intersectPlane(plane, target);
2619
2820
  if (intersection) {
2620
2821
  const gridX = Math.round((target.x - offsetX) / cellSize);
@@ -2652,7 +2853,7 @@ function useRaycaster(options) {
2652
2853
  return {
2653
2854
  gridX: gridCoords.x,
2654
2855
  gridZ: gridCoords.z,
2655
- worldPosition: new THREE10__namespace.Vector3(
2856
+ worldPosition: new THREE11__namespace.Vector3(
2656
2857
  gridCoords.x * cellSize + offsetX,
2657
2858
  0,
2658
2859
  gridCoords.z * cellSize + offsetZ
@@ -2682,7 +2883,7 @@ var DEFAULT_CONFIG = {
2682
2883
  };
2683
2884
  function gridToWorld(gridX, gridZ, config = DEFAULT_CONFIG) {
2684
2885
  const opts = { ...DEFAULT_CONFIG, ...config };
2685
- return new THREE10__namespace.Vector3(
2886
+ return new THREE11__namespace.Vector3(
2686
2887
  gridX * opts.cellSize + opts.offsetX,
2687
2888
  opts.elevation,
2688
2889
  gridZ * opts.cellSize + opts.offsetZ
@@ -2696,17 +2897,17 @@ function worldToGrid(worldX, worldZ, config = DEFAULT_CONFIG) {
2696
2897
  };
2697
2898
  }
2698
2899
  function raycastToPlane(camera, mouseX, mouseY, planeY = 0) {
2699
- const raycaster = new THREE10__namespace.Raycaster();
2700
- const mouse = new THREE10__namespace.Vector2(mouseX, mouseY);
2900
+ const raycaster = new THREE11__namespace.Raycaster();
2901
+ const mouse = new THREE11__namespace.Vector2(mouseX, mouseY);
2701
2902
  raycaster.setFromCamera(mouse, camera);
2702
- const plane = new THREE10__namespace.Plane(new THREE10__namespace.Vector3(0, 1, 0), -planeY);
2703
- const target = new THREE10__namespace.Vector3();
2903
+ const plane = new THREE11__namespace.Plane(new THREE11__namespace.Vector3(0, 1, 0), -planeY);
2904
+ const target = new THREE11__namespace.Vector3();
2704
2905
  const intersection = raycaster.ray.intersectPlane(plane, target);
2705
2906
  return intersection ? target : null;
2706
2907
  }
2707
2908
  function raycastToObjects(camera, mouseX, mouseY, objects) {
2708
- const raycaster = new THREE10__namespace.Raycaster();
2709
- const mouse = new THREE10__namespace.Vector2(mouseX, mouseY);
2909
+ const raycaster = new THREE11__namespace.Raycaster();
2910
+ const mouse = new THREE11__namespace.Vector2(mouseX, mouseY);
2710
2911
  raycaster.setFromCamera(mouse, camera);
2711
2912
  const intersects = raycaster.intersectObjects(objects, true);
2712
2913
  return intersects.length > 0 ? intersects[0] : null;
@@ -2758,14 +2959,14 @@ function getCellsInRadius(centerX, centerZ, radius) {
2758
2959
  return cells;
2759
2960
  }
2760
2961
  function createGridHighlight(color = 16776960, opacity = 0.3) {
2761
- const geometry = new THREE10__namespace.PlaneGeometry(0.95, 0.95);
2762
- const material = new THREE10__namespace.MeshBasicMaterial({
2962
+ const geometry = new THREE11__namespace.PlaneGeometry(0.95, 0.95);
2963
+ const material = new THREE11__namespace.MeshBasicMaterial({
2763
2964
  color,
2764
2965
  transparent: true,
2765
2966
  opacity,
2766
- side: THREE10__namespace.DoubleSide
2967
+ side: THREE11__namespace.DoubleSide
2767
2968
  });
2768
- const mesh = new THREE10__namespace.Mesh(geometry, material);
2969
+ const mesh = new THREE11__namespace.Mesh(geometry, material);
2769
2970
  mesh.rotation.x = -Math.PI / 2;
2770
2971
  mesh.position.y = 0.01;
2771
2972
  return mesh;
@@ -2778,31 +2979,31 @@ function normalizeMouseCoordinates(clientX, clientY, element) {
2778
2979
  };
2779
2980
  }
2780
2981
  function isInFrustum(position, camera, padding = 0) {
2781
- const frustum = new THREE10__namespace.Frustum();
2782
- const projScreenMatrix = new THREE10__namespace.Matrix4();
2982
+ const frustum = new THREE11__namespace.Frustum();
2983
+ const projScreenMatrix = new THREE11__namespace.Matrix4();
2783
2984
  projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
2784
2985
  frustum.setFromProjectionMatrix(projScreenMatrix);
2785
- const sphere = new THREE10__namespace.Sphere(position, padding);
2986
+ const sphere = new THREE11__namespace.Sphere(position, padding);
2786
2987
  return frustum.intersectsSphere(sphere);
2787
2988
  }
2788
2989
  function filterByFrustum(positions, camera, padding = 0) {
2789
- const frustum = new THREE10__namespace.Frustum();
2790
- const projScreenMatrix = new THREE10__namespace.Matrix4();
2990
+ const frustum = new THREE11__namespace.Frustum();
2991
+ const projScreenMatrix = new THREE11__namespace.Matrix4();
2791
2992
  projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
2792
2993
  frustum.setFromProjectionMatrix(projScreenMatrix);
2793
2994
  return positions.filter((position) => {
2794
- const sphere = new THREE10__namespace.Sphere(position, padding);
2995
+ const sphere = new THREE11__namespace.Sphere(position, padding);
2795
2996
  return frustum.intersectsSphere(sphere);
2796
2997
  });
2797
2998
  }
2798
2999
  function getVisibleIndices(positions, camera, padding = 0) {
2799
- const frustum = new THREE10__namespace.Frustum();
2800
- const projScreenMatrix = new THREE10__namespace.Matrix4();
3000
+ const frustum = new THREE11__namespace.Frustum();
3001
+ const projScreenMatrix = new THREE11__namespace.Matrix4();
2801
3002
  const visible = /* @__PURE__ */ new Set();
2802
3003
  projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
2803
3004
  frustum.setFromProjectionMatrix(projScreenMatrix);
2804
3005
  positions.forEach((position, index) => {
2805
- const sphere = new THREE10__namespace.Sphere(position, padding);
3006
+ const sphere = new THREE11__namespace.Sphere(position, padding);
2806
3007
  if (frustum.intersectsSphere(sphere)) {
2807
3008
  visible.add(index);
2808
3009
  }
@@ -2826,7 +3027,7 @@ function updateInstanceLOD(instancedMesh, positions, camera, lodDistances) {
2826
3027
  return lodIndices;
2827
3028
  }
2828
3029
  function cullInstancedMesh(instancedMesh, positions, visibleIndices) {
2829
- const dummy = new THREE10__namespace.Object3D();
3030
+ const dummy = new THREE11__namespace.Object3D();
2830
3031
  let visibleCount = 0;
2831
3032
  positions.forEach((position, index) => {
2832
3033
  if (visibleIndices.has(index)) {
@@ -3993,25 +4194,25 @@ function orbitRingPositions(count, radius, tilt) {
3993
4194
  return positions;
3994
4195
  }
3995
4196
  function arcCurve3D(from, to, offset) {
3996
- const start = new THREE10.Vector3(...from);
3997
- const end = new THREE10.Vector3(...to);
3998
- const mid = new THREE10.Vector3().addVectors(start, end).multiplyScalar(0.5);
3999
- const dir = new THREE10.Vector3().subVectors(end, start).normalize();
4000
- const up = new THREE10.Vector3(0, 1, 0);
4001
- const perp = new THREE10.Vector3().crossVectors(dir, up).normalize();
4197
+ const start = new THREE11.Vector3(...from);
4198
+ const end = new THREE11.Vector3(...to);
4199
+ const mid = new THREE11.Vector3().addVectors(start, end).multiplyScalar(0.5);
4200
+ const dir = new THREE11.Vector3().subVectors(end, start).normalize();
4201
+ const up = new THREE11.Vector3(0, 1, 0);
4202
+ const perp = new THREE11.Vector3().crossVectors(dir, up).normalize();
4002
4203
  if (perp.length() < 1e-3) {
4003
- perp.crossVectors(dir, new THREE10.Vector3(1, 0, 0)).normalize();
4204
+ perp.crossVectors(dir, new THREE11.Vector3(1, 0, 0)).normalize();
4004
4205
  }
4005
4206
  const control = mid.clone().add(perp.multiplyScalar(offset));
4006
4207
  control.y += Math.abs(offset) * 0.3;
4007
- return new THREE10.QuadraticBezierCurve3(start, control, end);
4208
+ return new THREE11.QuadraticBezierCurve3(start, control, end);
4008
4209
  }
4009
4210
  function selfLoopCurve3D(position, loopRadius) {
4010
- const base = new THREE10.Vector3(...position);
4011
- const start = base.clone().add(new THREE10.Vector3(-loopRadius * 0.3, 0, 0));
4012
- const end = base.clone().add(new THREE10.Vector3(loopRadius * 0.3, 0, 0));
4013
- const control = base.clone().add(new THREE10.Vector3(0, loopRadius, 0));
4014
- return new THREE10.QuadraticBezierCurve3(start, control, end);
4211
+ const base = new THREE11.Vector3(...position);
4212
+ const start = base.clone().add(new THREE11.Vector3(-loopRadius * 0.3, 0, 0));
4213
+ const end = base.clone().add(new THREE11.Vector3(loopRadius * 0.3, 0, 0));
4214
+ const control = base.clone().add(new THREE11.Vector3(0, loopRadius, 0));
4215
+ return new THREE11.QuadraticBezierCurve3(start, control, end);
4015
4216
  }
4016
4217
  function treeLayout3D(node, origin, horizontalSpacing, verticalSpacing = 2) {
4017
4218
  const results = [];
@@ -4178,7 +4379,7 @@ var Avl3DOrbitalNode = ({
4178
4379
  if (!groupRef.current) return;
4179
4380
  groupRef.current.rotation.y += delta * (hovered ? 0.4 : 0.2);
4180
4381
  groupRef.current.rotation.x += delta * 0.05;
4181
- currentScale.current = THREE10.MathUtils.damp(currentScale.current, targetScale, 6, delta);
4382
+ currentScale.current = THREE11.MathUtils.damp(currentScale.current, targetScale, 6, delta);
4182
4383
  });
4183
4384
  const baseBrightness = 0.3 + Math.min(pageCount, 5) * 0.05;
4184
4385
  const emissiveIntensity = hovered ? 0.8 : baseBrightness;
@@ -4820,7 +5021,7 @@ var Avl3DStateNode = ({
4820
5021
  const targetScale = hovered ? 1.08 : 1;
4821
5022
  const currentScale = React3.useRef(1);
4822
5023
  fiber.useFrame((_, delta) => {
4823
- currentScale.current = THREE10.MathUtils.damp(currentScale.current, targetScale, 6, delta);
5024
+ currentScale.current = THREE11.MathUtils.damp(currentScale.current, targetScale, 6, delta);
4824
5025
  });
4825
5026
  const scale = currentScale.current;
4826
5027
  return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
@@ -5000,9 +5201,9 @@ var Avl3DTransitionArc = ({
5000
5201
  const guardPt = curve.getPoint(0.3);
5001
5202
  const arrowPt = curve.getPoint(0.9);
5002
5203
  const arrowTangent = curve.getTangent(0.9);
5003
- const upVec = new THREE10.Vector3(0, 1, 0);
5004
- const tangentVec = new THREE10.Vector3(arrowTangent.x, arrowTangent.y, arrowTangent.z).normalize();
5005
- const quat = new THREE10.Quaternion().setFromUnitVectors(upVec, tangentVec);
5204
+ const upVec = new THREE11.Vector3(0, 1, 0);
5205
+ const tangentVec = new THREE11.Vector3(arrowTangent.x, arrowTangent.y, arrowTangent.z).normalize();
5206
+ const quat = new THREE11.Quaternion().setFromUnitVectors(upVec, tangentVec);
5006
5207
  const effectPositions2 = [];
5007
5208
  for (let ei = 0; ei < 4; ei++) {
5008
5209
  const t = 0.7 + ei * 0.05;
@@ -5226,14 +5427,14 @@ function operatorColor(label) {
5226
5427
  return "#4A90D9";
5227
5428
  }
5228
5429
  function edgeGeometry(parent, child) {
5229
- const p = new THREE10.Vector3(parent.x, parent.y, parent.z);
5230
- const c = new THREE10.Vector3(child.x, child.y, child.z);
5231
- const mid = new THREE10.Vector3().addVectors(p, c).multiplyScalar(0.5);
5232
- const dir = new THREE10.Vector3().subVectors(c, p);
5430
+ const p = new THREE11.Vector3(parent.x, parent.y, parent.z);
5431
+ const c = new THREE11.Vector3(child.x, child.y, child.z);
5432
+ const mid = new THREE11.Vector3().addVectors(p, c).multiplyScalar(0.5);
5433
+ const dir = new THREE11.Vector3().subVectors(c, p);
5233
5434
  const length = dir.length();
5234
- const yAxis = new THREE10.Vector3(0, 1, 0);
5435
+ const yAxis = new THREE11.Vector3(0, 1, 0);
5235
5436
  const angle = yAxis.angleTo(dir.normalize());
5236
- const axis = new THREE10.Vector3().crossVectors(yAxis, dir).normalize();
5437
+ const axis = new THREE11.Vector3().crossVectors(yAxis, dir).normalize();
5237
5438
  if (axis.length() < 1e-3) {
5238
5439
  return {
5239
5440
  position: [mid.x, mid.y, mid.z],
@@ -5609,12 +5810,12 @@ function useAvl3DConfig() {
5609
5810
  }
5610
5811
  function CameraController({ targetPosition, targetLookAt, animated }) {
5611
5812
  const { camera } = fiber.useThree();
5612
- const targetPosVec = React3.useRef(new THREE10__namespace.Vector3(...targetPosition));
5613
- const targetLookVec = React3.useRef(new THREE10__namespace.Vector3(...targetLookAt));
5813
+ const targetPosVec = React3.useRef(new THREE11__namespace.Vector3(...targetPosition));
5814
+ const targetLookVec = React3.useRef(new THREE11__namespace.Vector3(...targetLookAt));
5614
5815
  const isAnimating = React3.useRef(false);
5615
5816
  React3.useEffect(() => {
5616
- const newTarget = new THREE10__namespace.Vector3(...targetPosition);
5617
- const newLookAt = new THREE10__namespace.Vector3(...targetLookAt);
5817
+ const newTarget = new THREE11__namespace.Vector3(...targetPosition);
5818
+ const newLookAt = new THREE11__namespace.Vector3(...targetLookAt);
5618
5819
  if (!newTarget.equals(targetPosVec.current) || !newLookAt.equals(targetLookVec.current)) {
5619
5820
  targetPosVec.current.copy(newTarget);
5620
5821
  targetLookVec.current.copy(newLookAt);
@@ -5629,9 +5830,9 @@ function CameraController({ targetPosition, targetLookAt, animated }) {
5629
5830
  fiber.useFrame((_, delta) => {
5630
5831
  if (!isAnimating.current) return;
5631
5832
  const speed = 3;
5632
- camera.position.x = THREE10__namespace.MathUtils.damp(camera.position.x, targetPosVec.current.x, speed, delta);
5633
- camera.position.y = THREE10__namespace.MathUtils.damp(camera.position.y, targetPosVec.current.y, speed, delta);
5634
- camera.position.z = THREE10__namespace.MathUtils.damp(camera.position.z, targetPosVec.current.z, speed, delta);
5833
+ camera.position.x = THREE11__namespace.MathUtils.damp(camera.position.x, targetPosVec.current.x, speed, delta);
5834
+ camera.position.y = THREE11__namespace.MathUtils.damp(camera.position.y, targetPosVec.current.y, speed, delta);
5835
+ camera.position.z = THREE11__namespace.MathUtils.damp(camera.position.z, targetPosVec.current.z, speed, delta);
5635
5836
  camera.lookAt(targetLookVec.current);
5636
5837
  const dist = camera.position.distanceTo(targetPosVec.current);
5637
5838
  if (dist < 0.05) {
@@ -5646,7 +5847,7 @@ function SceneFade({ animating, children }) {
5646
5847
  fiber.useFrame((_, delta) => {
5647
5848
  if (!groupRef.current) return;
5648
5849
  const target = animating ? 0 : 1;
5649
- opacityRef.current = THREE10__namespace.MathUtils.damp(opacityRef.current, target, 5, delta);
5850
+ opacityRef.current = THREE11__namespace.MathUtils.damp(opacityRef.current, target, 5, delta);
5650
5851
  groupRef.current.visible = opacityRef.current > 0.05;
5651
5852
  const s = 0.9 + opacityRef.current * 0.1;
5652
5853
  groupRef.current.scale.setScalar(s);