@almadar/ui 5.141.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,9 +4,11 @@ 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
+ var RoomEnvironment_js = require('three/examples/jsm/environments/RoomEnvironment.js');
8
9
  var drei = require('@react-three/drei');
9
10
  var jsxRuntime = require('react/jsx-runtime');
11
+ var postprocessing = require('@react-three/postprocessing');
10
12
  var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
11
13
  var SkeletonUtils = require('three/examples/jsm/utils/SkeletonUtils');
12
14
  var clsx = require('clsx');
@@ -14,7 +16,6 @@ var tailwindMerge = require('tailwind-merge');
14
16
  var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
15
17
  var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
16
18
  var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
17
- var postprocessing = require('@react-three/postprocessing');
18
19
  var hooks = require('@almadar/ui/hooks');
19
20
 
20
21
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -38,7 +39,7 @@ function _interopNamespace(e) {
38
39
  }
39
40
 
40
41
  var React3__default = /*#__PURE__*/_interopDefault(React3);
41
- var THREE10__namespace = /*#__PURE__*/_interopNamespace(THREE10);
42
+ var THREE11__namespace = /*#__PURE__*/_interopNamespace(THREE11);
42
43
 
43
44
  var __defProp = Object.defineProperty;
44
45
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -474,6 +475,10 @@ function Lighting3D({
474
475
  directionalIntensity = 0.8,
475
476
  directionalColor = "#ffffff",
476
477
  directionalPosition = [10, 20, 10],
478
+ hemisphereIntensity = 0.3,
479
+ hemisphereColor = "#87ceeb",
480
+ hemisphereGroundColor = "#362d1d",
481
+ points,
477
482
  shadows = true,
478
483
  shadowMapSize = 2048,
479
484
  shadowCameraSize = 20,
@@ -506,22 +511,63 @@ function Lighting3D({
506
511
  /* @__PURE__ */ jsxRuntime.jsx(
507
512
  "hemisphereLight",
508
513
  {
509
- intensity: 0.3,
510
- color: "#87ceeb",
511
- groundColor: "#362d1d"
514
+ intensity: hemisphereIntensity,
515
+ color: hemisphereColor,
516
+ groundColor: hemisphereGroundColor
512
517
  }
513
518
  ),
519
+ points?.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
520
+ "pointLight",
521
+ {
522
+ position: p.position,
523
+ intensity: p.intensity,
524
+ color: p.color,
525
+ distance: p.distance,
526
+ decay: p.decay
527
+ },
528
+ i
529
+ )),
514
530
  showHelpers && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
515
531
  "directionalLightHelper",
516
532
  {
517
533
  args: [
518
- new THREE10__namespace.DirectionalLight(directionalColor, directionalIntensity),
534
+ new THREE11__namespace.DirectionalLight(directionalColor, directionalIntensity),
519
535
  5
520
536
  ]
521
537
  }
522
538
  ) })
523
539
  ] });
524
540
  }
541
+ function Effects3D({ post }) {
542
+ if (!post || !post.bloom && !post.vignette) return null;
543
+ const passes = [];
544
+ if (post.bloom) {
545
+ passes.push(
546
+ /* @__PURE__ */ jsxRuntime.jsx(
547
+ postprocessing.Bloom,
548
+ {
549
+ intensity: post.bloom.intensity ?? 1,
550
+ luminanceThreshold: post.bloom.threshold ?? 0.9,
551
+ luminanceSmoothing: post.bloom.smoothing ?? 0.3
552
+ },
553
+ "bloom"
554
+ )
555
+ );
556
+ }
557
+ if (post.vignette) {
558
+ passes.push(
559
+ /* @__PURE__ */ jsxRuntime.jsx(
560
+ postprocessing.Vignette,
561
+ {
562
+ offset: post.vignette.offset ?? 0.3,
563
+ darkness: post.vignette.darkness ?? 0.6
564
+ },
565
+ "vignette"
566
+ )
567
+ );
568
+ }
569
+ return /* @__PURE__ */ jsxRuntime.jsx(postprocessing.EffectComposer, { children: passes });
570
+ }
525
571
  function CameraController3D({
526
572
  onCameraChange
527
573
  }) {
@@ -542,8 +588,8 @@ function FollowCamera3D({
542
588
  offset
543
589
  }) {
544
590
  const { camera } = fiber.useThree();
545
- const look = React3.useRef(new THREE10__namespace.Vector3(target[0], target[1], target[2]));
546
- 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());
547
593
  fiber.useFrame((_, delta) => {
548
594
  const t = Math.min(1, delta * 5);
549
595
  goal.current.set(target[0] + offset[0], target[1] + offset[1], target[2] + offset[2]);
@@ -564,6 +610,179 @@ function create3DProjector(opts = {}) {
564
610
  toWorld: (pos) => [pos.x * cellSize + offsetX, pos.z ?? 0, pos.y * cellSize + offsetZ]
565
611
  };
566
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;
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 = [
716
+ "offsetX",
717
+ "offsetY",
718
+ "rotate",
719
+ "opacity",
720
+ "radiusX",
721
+ "radiusY",
722
+ "width",
723
+ "height",
724
+ "strokeWidth",
725
+ "strokeDashOffset",
726
+ "blur"
727
+ ];
728
+ function isAnimatedShape(node) {
729
+ return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
730
+ }
731
+ var lerp2 = (a, b, k) => a + (b - a) * k;
732
+ function applyShapeAnimation(node, timeMs) {
733
+ const anim = node.animation;
734
+ if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return node;
735
+ const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
736
+ const cycle = timeMs / anim.durationMs;
737
+ const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
738
+ const out = { ...node };
739
+ const trackValue = (key) => {
740
+ const defined = frames.filter((f) => f[key] !== void 0);
741
+ if (defined.length === 0) return void 0;
742
+ let prev;
743
+ let next;
744
+ for (const f of defined) {
745
+ if (f.at <= t) prev = f;
746
+ else if (!next) next = f;
747
+ }
748
+ if (!prev) return defined[0][key];
749
+ if (!next) return prev[key];
750
+ const span = next.at - prev.at;
751
+ const k = span > 0 ? (t - prev.at) / span : 1;
752
+ const a = prev[key];
753
+ const b = next[key];
754
+ if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
755
+ return a;
756
+ };
757
+ for (const key of NUMERIC_TRACKS2) {
758
+ const v = trackValue(key);
759
+ if (v !== void 0) out[key] = v;
760
+ }
761
+ const fill = trackValue("fill");
762
+ if (fill !== void 0) out.fill = fill;
763
+ const stroke = trackValue("stroke");
764
+ if (stroke !== void 0) out.stroke = stroke;
765
+ const shadowFrames = frames.filter((f) => f.shadow !== void 0);
766
+ if (shadowFrames.length > 0) {
767
+ const sh = trackValue("shadow");
768
+ if (sh !== void 0) {
769
+ let prevSh;
770
+ let nextSh;
771
+ for (const f of shadowFrames) {
772
+ if (f.at <= t) prevSh = f;
773
+ else if (!nextSh) nextSh = f;
774
+ }
775
+ if (prevSh?.shadow && nextSh?.shadow) {
776
+ const span = nextSh.at - prevSh.at;
777
+ const k = span > 0 ? (t - prevSh.at) / span : 1;
778
+ out.shadow = { color: prevSh.shadow.color, blur: lerp2(prevSh.shadow.blur, nextSh.shadow.blur, k) };
779
+ } else {
780
+ out.shadow = sh;
781
+ }
782
+ }
783
+ }
784
+ return out;
785
+ }
567
786
 
568
787
  // lib/atlasSlice.ts
569
788
  var atlasCache = /* @__PURE__ */ new Map();
@@ -699,12 +918,12 @@ function ModelLoader({
699
918
  if (!loadedModel) return null;
700
919
  const cloned = SkeletonUtils.clone(loadedModel);
701
920
  cloned.updateMatrixWorld(true);
702
- const tintColor = tint ? new THREE10__namespace.Color(tint) : null;
921
+ const tintColor = tint ? new THREE11__namespace.Color(tint) : null;
703
922
  cloned.traverse((child) => {
704
- if (child instanceof THREE10__namespace.Mesh) {
923
+ if (child instanceof THREE11__namespace.Mesh) {
705
924
  child.castShadow = castShadow;
706
925
  child.receiveShadow = receiveShadow;
707
- if (tintColor && child.material instanceof THREE10__namespace.MeshStandardMaterial) {
926
+ if (tintColor && child.material instanceof THREE11__namespace.MeshStandardMaterial) {
708
927
  const mat = child.material.clone();
709
928
  mat.color.multiply(tintColor);
710
929
  child.material = mat;
@@ -713,7 +932,7 @@ function ModelLoader({
713
932
  });
714
933
  return cloned;
715
934
  }, [loadedModel, castShadow, receiveShadow, tint]);
716
- 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]);
717
936
  React3.useEffect(() => {
718
937
  if (!mixer || !animation || clips.length === 0) return;
719
938
  const wanted = animation.toLowerCase();
@@ -730,8 +949,8 @@ function ModelLoader({
730
949
  });
731
950
  const normFactor = React3.useMemo(() => {
732
951
  if (!model) return 1;
733
- const box = new THREE10__namespace.Box3().setFromObject(model);
734
- const size = new THREE10__namespace.Vector3();
952
+ const box = new THREE11__namespace.Box3().setFromObject(model);
953
+ const size = new THREE11__namespace.Vector3();
735
954
  box.getSize(size);
736
955
  const maxDim = Math.max(size.x, size.y, size.z);
737
956
  if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
@@ -821,7 +1040,7 @@ var warnUnsupported3d = (kind) => {
821
1040
  warnedUnsupported.add(kind);
822
1041
  mesh3dLog.warn("unsupported drawable kind on the 3D backend \u2014 skipped", { kind });
823
1042
  };
824
- var CrossOriginTextureLoader = class extends THREE10__namespace.TextureLoader {
1043
+ var CrossOriginTextureLoader = class extends THREE11__namespace.TextureLoader {
825
1044
  constructor() {
826
1045
  super();
827
1046
  this.crossOrigin = "anonymous";
@@ -839,7 +1058,7 @@ function useBillboardTexture(url) {
839
1058
  url,
840
1059
  (texture) => {
841
1060
  if (!active) return;
842
- texture.colorSpace = THREE10__namespace.SRGBColorSpace;
1061
+ texture.colorSpace = THREE11__namespace.SRGBColorSpace;
843
1062
  setState({ texture, error: false });
844
1063
  },
845
1064
  void 0,
@@ -892,7 +1111,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
892
1111
  }, [texture, frame, node.height, node.width, anchor, cellSize]);
893
1112
  const groundGeometry = React3__default.default.useMemo(() => {
894
1113
  if (anchor !== "top-left" || !texture || !atlasReady) return null;
895
- const g = new THREE10__namespace.PlaneGeometry(size.width, size.height);
1114
+ const g = new THREE11__namespace.PlaneGeometry(size.width, size.height);
896
1115
  g.rotateX(-Math.PI / 2);
897
1116
  return g;
898
1117
  }, [anchor, texture, atlasReady, size.width, size.height]);
@@ -900,15 +1119,15 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
900
1119
  if (anchor === "top-left") {
901
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: [
902
1121
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
903
- /* @__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 })
904
1123
  ] }) });
905
1124
  }
906
1125
  return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [world[0], world[1] + size.height / 2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { children: [
907
1126
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
908
- /* @__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 })
909
1128
  ] }) });
910
1129
  }
911
- texture.magFilter = texture.minFilter = THREE10__namespace.NearestFilter;
1130
+ texture.magFilter = texture.minFilter = THREE11__namespace.NearestFilter;
912
1131
  texture.needsUpdate = true;
913
1132
  if (frame) {
914
1133
  texture.repeat.set(frame.w / size.imgW, frame.h / size.imgH);
@@ -921,7 +1140,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
921
1140
  map: texture,
922
1141
  transparent: true,
923
1142
  alphaTest: 0.1,
924
- side: THREE10__namespace.DoubleSide,
1143
+ side: THREE11__namespace.DoubleSide,
925
1144
  opacity: (node.opacity ?? 1) * groupOpacity
926
1145
  }
927
1146
  ) }) });
@@ -934,7 +1153,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
934
1153
  map: texture,
935
1154
  transparent: true,
936
1155
  alphaTest: 0.1,
937
- side: THREE10__namespace.DoubleSide,
1156
+ side: THREE11__namespace.DoubleSide,
938
1157
  opacity: node.opacity ?? 1
939
1158
  }
940
1159
  )
@@ -965,8 +1184,27 @@ function Sprite3D({ node, projector, groupOpacity = 1 }) {
965
1184
  return /* @__PURE__ */ jsxRuntime.jsx(SpriteBillboard, { node, world: projector.toWorld(node.position), cellSize: projector.cellSize, groupOpacity });
966
1185
  }
967
1186
  function Shape3D({ node, projector, groupOpacity = 1 }) {
968
- if (!isValidScenePos(node.position)) return null;
969
- const world = projector.toWorld(node.position);
1187
+ const groupRef = React3__default.default.useRef(null);
1188
+ const materialRef = React3__default.default.useRef(null);
1189
+ const animated = isAnimatedShape(node);
1190
+ const validPos = isValidScenePos(node.position);
1191
+ const world = validPos ? projector.toWorld(node.position) : [0, 0, 0];
1192
+ fiber.useFrame(({ clock }) => {
1193
+ if (!animated || !groupRef.current) return;
1194
+ const view = applyShapeAnimation(node, clock.elapsedTime * 1e3);
1195
+ groupRef.current.position.set(
1196
+ world[0] + (view.offsetX ?? 0) * projector.cellSize,
1197
+ world[1] + 0.02,
1198
+ world[2] + (view.offsetY ?? 0) * projector.cellSize
1199
+ );
1200
+ groupRef.current.rotation.y = -(view.rotate ?? 0);
1201
+ const mat = materialRef.current;
1202
+ if (mat) {
1203
+ mat.opacity = (view.opacity ?? node.opacity ?? 1) * groupOpacity;
1204
+ if (view.fill) mat.color.set(view.fill);
1205
+ }
1206
+ });
1207
+ if (!validPos) return null;
970
1208
  const color = node.fill ?? node.stroke ?? "#ffffff";
971
1209
  let geometry;
972
1210
  switch (node.shape) {
@@ -984,7 +1222,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
984
1222
  }
985
1223
  case "poly": {
986
1224
  if (!node.points || node.points.length === 0) return null;
987
- const s = new THREE10__namespace.Shape();
1225
+ const s = new THREE11__namespace.Shape();
988
1226
  node.points.forEach((p, i) => {
989
1227
  if (i === 0) s.moveTo(p.x, p.y);
990
1228
  else s.lineTo(p.x, p.y);
@@ -1000,12 +1238,12 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
1000
1238
  default:
1001
1239
  return null;
1002
1240
  }
1003
- return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], position: [world[0], world[1] + 0.02, world[2]], children: [
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: [
1004
1242
  geometry,
1005
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE10__namespace.DoubleSide })
1006
- ] });
1243
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE11__namespace.DoubleSide })
1244
+ ] }) });
1007
1245
  }
1008
- function Text3D({ node, projector }) {
1246
+ function Text3D({ node, projector, groupOpacity = 1 }) {
1009
1247
  if (!isValidScenePos(node.position)) return null;
1010
1248
  const world = projector.toWorld(node.position);
1011
1249
  return /* @__PURE__ */ jsxRuntime.jsx(drei.Billboard, { position: [world[0], world[1] + 1.2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -1017,68 +1255,52 @@ function Text3D({ node, projector }) {
1017
1255
  anchorY: "middle",
1018
1256
  outlineWidth: 0.02,
1019
1257
  outlineColor: "#000000",
1258
+ fillOpacity: groupOpacity,
1259
+ outlineOpacity: groupOpacity,
1020
1260
  children: node.text
1021
1261
  }
1022
1262
  ) });
1023
1263
  }
1024
- var MESH_SEGMENTS_DEFAULT = 24;
1025
- function clampSegments(segments) {
1026
- const s = segments ?? MESH_SEGMENTS_DEFAULT;
1027
- return Math.min(64, Math.max(3, Math.round(s)));
1028
- }
1029
- function isAnimatedMesh(node) {
1030
- return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
1031
- }
1032
- var lerp = (a, b, k) => a + (b - a) * k;
1033
- var NUMERIC_TRACKS = [
1034
- "offsetX",
1035
- "offsetY",
1036
- "offsetZ",
1037
- "rotateX",
1038
- "rotateY",
1039
- "rotateZ",
1040
- "scale",
1041
- "opacity",
1042
- "emissiveIntensity"
1043
- ];
1044
- function applyMeshAnimation(node, timeMs) {
1045
- const anim = node.animation;
1046
- if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
1047
- const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
1048
- const cycle = timeMs / anim.durationMs;
1049
- const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
1050
- const trackValue = (key) => {
1051
- const defined = frames.filter((f) => f[key] !== void 0);
1052
- if (defined.length === 0) return void 0;
1053
- let prev;
1054
- let next;
1055
- for (const f of defined) {
1056
- if (f.at <= t) prev = f;
1057
- 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
+ }
1058
1298
  }
1059
- if (!prev) return defined[0][key];
1060
- if (!next) return prev[key];
1061
- const span = next.at - prev.at;
1062
- const k = span > 0 ? (t - prev.at) / span : 1;
1063
- const a = prev[key];
1064
- const b = next[key];
1065
- if (typeof a === "number" && typeof b === "number") return lerp(a, b, k);
1066
- return a;
1067
- };
1068
- const num = {};
1069
- for (const key of NUMERIC_TRACKS) {
1070
- const v = trackValue(key);
1071
- 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));
1072
1301
  }
1073
- return {
1074
- offset: [num.offsetX ?? 0, num.offsetY ?? 0, num.offsetZ ?? 0],
1075
- rotate: [num.rotateX ?? 0, num.rotateY ?? 0, num.rotateZ ?? 0],
1076
- scale: num.scale ?? 1,
1077
- opacity: num.opacity,
1078
- emissiveIntensity: num.emissiveIntensity,
1079
- color: trackValue("color"),
1080
- emissive: trackValue("emissive")
1081
- };
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 };
1082
1304
  }
1083
1305
  function meshGeometry(node, cellSize) {
1084
1306
  const seg = clampSegments(node.segments);
@@ -1106,17 +1328,20 @@ function meshGeometry(node, cellSize) {
1106
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 };
1107
1329
  }
1108
1330
  case "plane":
1109
- 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 };
1110
1332
  case "circle":
1111
- 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);
1112
1336
  default:
1113
1337
  return null;
1114
1338
  }
1115
1339
  }
1340
+ var warnedPolyhedronOutline = false;
1116
1341
  var SIDE_MAP = {
1117
- front: THREE10__namespace.FrontSide,
1118
- back: THREE10__namespace.BackSide,
1119
- double: THREE10__namespace.DoubleSide
1342
+ front: THREE11__namespace.FrontSide,
1343
+ back: THREE11__namespace.BackSide,
1344
+ double: THREE11__namespace.DoubleSide
1120
1345
  };
1121
1346
  function meshMaterial(mat, opacity, ref) {
1122
1347
  const m = mat ?? {};
@@ -1160,6 +1385,53 @@ function meshMaterial(mat, opacity, ref) {
1160
1385
  );
1161
1386
  }
1162
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
+ }
1163
1435
  function Mesh3D({
1164
1436
  node,
1165
1437
  projector,
@@ -1172,6 +1444,10 @@ function Mesh3D({
1172
1444
  const validPos = isValidScenePos(node.position);
1173
1445
  const baseWorld = validPos ? projector.toWorld(node.position) : [0, 0, 0];
1174
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]);
1175
1451
  fiber.useFrame(({ clock }) => {
1176
1452
  if (!animated || !groupRef.current) return;
1177
1453
  const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
@@ -1184,8 +1460,13 @@ function Mesh3D({
1184
1460
  );
1185
1461
  groupRef.current.scale.setScalar(state.scale);
1186
1462
  if (meshRef.current) {
1463
+ const shapeRot = geo?.baseRotation ?? [0, 0, 0];
1187
1464
  const base = node.rotation ?? [0, 0, 0];
1188
- 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
+ );
1189
1470
  }
1190
1471
  const mat = materialRef.current;
1191
1472
  if (mat) {
@@ -1202,13 +1483,28 @@ function Mesh3D({
1202
1483
  if (!validPos || !geo) return null;
1203
1484
  const lift = (node.pivot ?? "bottom") === "bottom" ? geo.lift : 0;
1204
1485
  const opacity = (node.opacity ?? 1) * (node.material?.opacity ?? 1) * groupOpacity;
1205
- 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
+ ];
1206
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 } : {};
1207
1502
  return /* @__PURE__ */ jsxRuntime.jsxs("group", { ref: groupRef, position: baseWorld, children: [
1208
1503
  /* @__PURE__ */ jsxRuntime.jsxs(
1209
1504
  "mesh",
1210
1505
  {
1211
1506
  ref: meshRef,
1507
+ ...geometryProp,
1212
1508
  position: [0, lift, 0],
1213
1509
  rotation,
1214
1510
  castShadow: node.castShadow ?? true,
@@ -1219,13 +1515,13 @@ function Mesh3D({
1219
1515
  ]
1220
1516
  }
1221
1517
  ),
1222
- 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: [
1223
1519
  geo.element,
1224
1520
  /* @__PURE__ */ jsxRuntime.jsx(
1225
1521
  "meshBasicMaterial",
1226
1522
  {
1227
1523
  color: node.outline.color ?? "#101014",
1228
- side: THREE10__namespace.BackSide,
1524
+ side: THREE11__namespace.BackSide,
1229
1525
  transparent: opacity < 1,
1230
1526
  opacity
1231
1527
  }
@@ -1240,7 +1536,7 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
1240
1536
  case "draw-shape":
1241
1537
  return /* @__PURE__ */ jsxRuntime.jsx(Shape3D, { node, projector, groupOpacity });
1242
1538
  case "draw-text":
1243
- return /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node, projector });
1539
+ return /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node, projector, groupOpacity });
1244
1540
  case "draw-mesh":
1245
1541
  return /* @__PURE__ */ jsxRuntime.jsx(Mesh3D, { node, projector, groupOpacity });
1246
1542
  case "draw-sprite-layer":
@@ -1248,18 +1544,57 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
1248
1544
  case "draw-shape-layer":
1249
1545
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Shape3D, { node: item, projector, groupOpacity }, i)) });
1250
1546
  case "draw-text-layer":
1251
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node: item, projector }, i)) });
1547
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node: item, projector, groupOpacity }, i)) });
1252
1548
  case "draw-group": {
1253
1549
  if (!isValidScenePos(node.position) || !Array.isArray(node.items)) return null;
1254
1550
  if (node.clip) warnUnsupported3d("draw-group:clip");
1255
- const world = projector.toWorld(node.position);
1256
- const inner = create3DProjector({ cellSize: projector.cellSize });
1257
- const opacity = (node.opacity ?? 1) * groupOpacity;
1258
- const s = node.scale ?? 1;
1259
- 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 });
1260
1552
  }
1261
1553
  }
1262
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
+ }
1263
1598
 
1264
1599
  // lib/drawable/three/game3dTheme.ts
1265
1600
  var GRID_COLORS_3D = {
@@ -1272,6 +1607,20 @@ function cn(...inputs) {
1272
1607
  }
1273
1608
  var DEFAULT_GRID_CONFIG = {
1274
1609
  cellSize: 1};
1610
+ function RoomEnvironment3D() {
1611
+ const { gl, scene } = fiber.useThree(({ gl: gl2, scene: scene2 }) => ({ gl: gl2, scene: scene2 }));
1612
+ React3.useEffect(() => {
1613
+ const pmremGenerator = new THREE11__namespace.PMREMGenerator(gl);
1614
+ const envTexture = pmremGenerator.fromScene(new RoomEnvironment_js.RoomEnvironment(), 0.04).texture;
1615
+ scene.environment = envTexture;
1616
+ return () => {
1617
+ scene.environment = null;
1618
+ envTexture.dispose();
1619
+ pmremGenerator.dispose();
1620
+ };
1621
+ }, [gl, scene]);
1622
+ return null;
1623
+ }
1275
1624
  var Canvas3DHost = React3.forwardRef(
1276
1625
  ({
1277
1626
  cameraMode = "isometric",
@@ -1297,6 +1646,8 @@ var Canvas3DHost = React3.forwardRef(
1297
1646
  keyUpMap,
1298
1647
  pixelsPerUnit,
1299
1648
  fov,
1649
+ lighting,
1650
+ post,
1300
1651
  children,
1301
1652
  drawables
1302
1653
  }, ref) => {
@@ -1305,6 +1656,7 @@ var Canvas3DHost = React3.forwardRef(
1305
1656
  const [internalError, setInternalError] = React3.useState(null);
1306
1657
  const eventBus = useEventBus();
1307
1658
  const keysRef = React3.useRef(/* @__PURE__ */ new Set());
1659
+ const allDrawables = React3.useMemo(() => drawables ?? [], [drawables]);
1308
1660
  React3.useEffect(() => {
1309
1661
  if (!keyMap && !keyUpMap) return;
1310
1662
  const down = (e) => {
@@ -1338,7 +1690,7 @@ var Canvas3DHost = React3.forwardRef(
1338
1690
  unitAnimationEvent,
1339
1691
  cameraChangeEvent
1340
1692
  });
1341
- const drawnItems = React3.useMemo(() => collectDrawnItems(drawables ?? []), [drawables]);
1693
+ const drawnItems = React3.useMemo(() => collectDrawnItems(allDrawables), [allDrawables]);
1342
1694
  const scenePositions = React3.useMemo(() => drawnItems.map((i) => i.pos), [drawnItems]);
1343
1695
  const hitIndex = React3.useMemo(() => buildHitIndex(drawnItems), [drawnItems]);
1344
1696
  const gridBounds = React3.useMemo(() => {
@@ -1374,6 +1726,7 @@ var Canvas3DHost = React3.forwardRef(
1374
1726
  }),
1375
1727
  [gridBounds, cellSize]
1376
1728
  );
1729
+ const boneStore = React3.useMemo(() => new BoneStore(), []);
1377
1730
  const drawableProjector = React3.useMemo(
1378
1731
  () => create3DProjector({
1379
1732
  cellSize: gridConfig.cellSize,
@@ -1386,7 +1739,7 @@ var Canvas3DHost = React3.forwardRef(
1386
1739
  getCameraPosition: () => {
1387
1740
  if (controlsRef.current) {
1388
1741
  const pos = controlsRef.current.object.position;
1389
- return new THREE10__namespace.Vector3(pos.x, pos.y, pos.z);
1742
+ return new THREE11__namespace.Vector3(pos.x, pos.y, pos.z);
1390
1743
  }
1391
1744
  return null;
1392
1745
  },
@@ -1431,6 +1784,8 @@ var Canvas3DHost = React3.forwardRef(
1431
1784
  return { position: [cx + d, d * 0.8, cz + d], fov: fovDeg };
1432
1785
  case "top-down":
1433
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 };
1434
1789
  case "follow":
1435
1790
  return { position: [cx, d * 0.5, cz + d], fov: fovDeg };
1436
1791
  case "perspective":
@@ -1497,6 +1852,7 @@ var Canvas3DHost = React3.forwardRef(
1497
1852
  fiber.Canvas,
1498
1853
  {
1499
1854
  shadows,
1855
+ flat: lighting?.toneMapping === "none",
1500
1856
  camera: {
1501
1857
  position: cameraConfig.position,
1502
1858
  fov: cameraConfig.fov,
@@ -1520,9 +1876,19 @@ var Canvas3DHost = React3.forwardRef(
1520
1876
  shadowNormalBias: 0.04,
1521
1877
  shadowCameraSize: 5,
1522
1878
  shadowCameraNear: 0.5,
1523
- shadowCameraFar: 500
1879
+ shadowCameraFar: 500,
1880
+ ambientIntensity: lighting?.ambient?.intensity,
1881
+ ambientColor: lighting?.ambient?.color,
1882
+ directionalIntensity: lighting?.directional?.intensity,
1883
+ directionalColor: lighting?.directional?.color,
1884
+ directionalPosition: lighting?.directional?.position,
1885
+ hemisphereIntensity: lighting?.hemisphere?.intensity,
1886
+ hemisphereColor: lighting?.hemisphere?.color,
1887
+ hemisphereGroundColor: lighting?.hemisphere?.groundColor,
1888
+ points: lighting?.points
1524
1889
  }
1525
1890
  ),
1891
+ lighting?.environment === "room" && /* @__PURE__ */ jsxRuntime.jsx(RoomEnvironment3D, {}),
1526
1892
  showGrid && /* @__PURE__ */ jsxRuntime.jsx(
1527
1893
  drei.Grid,
1528
1894
  {
@@ -1545,7 +1911,7 @@ var Canvas3DHost = React3.forwardRef(
1545
1911
  fadeStrength: 1
1546
1912
  }
1547
1913
  ),
1548
- drawables && drawables.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("group", { children: drawables.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)) }) }),
1549
1915
  (tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxRuntime.jsxs(
1550
1916
  "mesh",
1551
1917
  {
@@ -1570,7 +1936,7 @@ var Canvas3DHost = React3.forwardRef(
1570
1936
  ]
1571
1937
  }
1572
1938
  ),
1573
- children,
1939
+ post && (post.bloom || post.vignette) ? /* @__PURE__ */ jsxRuntime.jsx(Effects3D, { post }) : null,
1574
1940
  /* @__PURE__ */ jsxRuntime.jsx(
1575
1941
  drei.OrbitControls,
1576
1942
  {
@@ -1581,7 +1947,7 @@ var Canvas3DHost = React3.forwardRef(
1581
1947
  dampingFactor: 0.05,
1582
1948
  enableZoom: true,
1583
1949
  enablePan: true,
1584
- 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 },
1585
1951
  minDistance: 2,
1586
1952
  maxDistance: 100,
1587
1953
  maxPolarAngle: Math.PI / 2 - 0.1
@@ -1604,15 +1970,15 @@ function Scene3D({ background = "#1a1a2e", fog, children }) {
1604
1970
  if (initializedRef.current) return;
1605
1971
  initializedRef.current = true;
1606
1972
  if (background.startsWith("#") || background.startsWith("rgb")) {
1607
- scene.background = new THREE10__namespace.Color(background);
1973
+ scene.background = new THREE11__namespace.Color(background);
1608
1974
  } else {
1609
- const loader = new THREE10__namespace.TextureLoader();
1975
+ const loader = new THREE11__namespace.TextureLoader();
1610
1976
  loader.load(background, (texture) => {
1611
1977
  scene.background = texture;
1612
1978
  });
1613
1979
  }
1614
1980
  if (fog) {
1615
- 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);
1616
1982
  }
1617
1983
  return () => {
1618
1984
  scene.background = null;
@@ -1635,14 +2001,14 @@ var Camera3D = React3.forwardRef(
1635
2001
  }, ref) => {
1636
2002
  const { camera, set, viewport } = fiber.useThree();
1637
2003
  const controlsRef = React3.useRef(null);
1638
- const initialPosition = React3.useRef(new THREE10__namespace.Vector3(...position));
1639
- 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));
1640
2006
  React3.useEffect(() => {
1641
2007
  let newCamera;
1642
2008
  if (mode === "isometric") {
1643
2009
  const aspect = viewport.aspect;
1644
2010
  const size = 10 / zoom;
1645
- newCamera = new THREE10__namespace.OrthographicCamera(
2011
+ newCamera = new THREE11__namespace.OrthographicCamera(
1646
2012
  -size * aspect,
1647
2013
  size * aspect,
1648
2014
  size,
@@ -1651,7 +2017,7 @@ var Camera3D = React3.forwardRef(
1651
2017
  1e3
1652
2018
  );
1653
2019
  } else {
1654
- newCamera = new THREE10__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
2020
+ newCamera = new THREE11__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
1655
2021
  }
1656
2022
  newCamera.position.copy(initialPosition.current);
1657
2023
  newCamera.lookAt(initialTarget.current.x, initialTarget.current.y, initialTarget.current.z);
@@ -1692,8 +2058,8 @@ var Camera3D = React3.forwardRef(
1692
2058
  }
1693
2059
  },
1694
2060
  getViewBounds: () => {
1695
- const min = new THREE10__namespace.Vector3(-10, -10, -10);
1696
- 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);
1697
2063
  return { min, max };
1698
2064
  }
1699
2065
  }));
@@ -1735,7 +2101,7 @@ var AssetLoader = class {
1735
2101
  __publicField(this, "textureCache");
1736
2102
  __publicField(this, "loadingPromises");
1737
2103
  this.objLoader = new OBJLoader_js.OBJLoader();
1738
- this.textureLoader = new THREE10__namespace.TextureLoader();
2104
+ this.textureLoader = new THREE11__namespace.TextureLoader();
1739
2105
  this.modelCache = /* @__PURE__ */ new Map();
1740
2106
  this.textureCache = /* @__PURE__ */ new Map();
1741
2107
  this.loadingPromises = /* @__PURE__ */ new Map();
@@ -1809,7 +2175,7 @@ var AssetLoader = class {
1809
2175
  return this.loadingPromises.get(`texture:${url}`);
1810
2176
  }
1811
2177
  const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
1812
- texture.colorSpace = THREE10__namespace.SRGBColorSpace;
2178
+ texture.colorSpace = THREE11__namespace.SRGBColorSpace;
1813
2179
  this.textureCache.set(url, texture);
1814
2180
  this.loadingPromises.delete(`texture:${url}`);
1815
2181
  return texture;
@@ -1883,7 +2249,7 @@ var AssetLoader = class {
1883
2249
  });
1884
2250
  this.modelCache.forEach((model) => {
1885
2251
  model.scene.traverse((child) => {
1886
- if (child instanceof THREE10__namespace.Mesh) {
2252
+ if (child instanceof THREE11__namespace.Mesh) {
1887
2253
  child.geometry.dispose();
1888
2254
  if (Array.isArray(child.material)) {
1889
2255
  child.material.forEach((m) => m.dispose());
@@ -1920,7 +2286,7 @@ var DEFAULT_OPTIONS = {
1920
2286
  gridSize: 20,
1921
2287
  assetLoader: new AssetLoader()
1922
2288
  };
1923
- function useThree4(options = {}) {
2289
+ function useThree5(options = {}) {
1924
2290
  const opts = { ...DEFAULT_OPTIONS, ...options };
1925
2291
  const containerRef = React3.useRef(null);
1926
2292
  const canvasRef = React3.useRef(null);
@@ -1933,21 +2299,21 @@ function useThree4(options = {}) {
1933
2299
  const [isReady, setIsReady] = React3.useState(false);
1934
2300
  const [dimensions, setDimensions] = React3.useState({ width: 0, height: 0 });
1935
2301
  const initialCameraPosition = React3.useMemo(
1936
- () => new THREE10__namespace.Vector3(...opts.cameraPosition),
2302
+ () => new THREE11__namespace.Vector3(...opts.cameraPosition),
1937
2303
  []
1938
2304
  );
1939
2305
  React3.useEffect(() => {
1940
2306
  if (!containerRef.current) return;
1941
2307
  const container = containerRef.current;
1942
2308
  const { clientWidth, clientHeight } = container;
1943
- const scene = new THREE10__namespace.Scene();
1944
- scene.background = new THREE10__namespace.Color(opts.backgroundColor);
2309
+ const scene = new THREE11__namespace.Scene();
2310
+ scene.background = new THREE11__namespace.Color(opts.backgroundColor);
1945
2311
  sceneRef.current = scene;
1946
2312
  let camera;
1947
2313
  const aspect = clientWidth / clientHeight;
1948
2314
  if (opts.cameraMode === "isometric") {
1949
2315
  const size = 10;
1950
- camera = new THREE10__namespace.OrthographicCamera(
2316
+ camera = new THREE11__namespace.OrthographicCamera(
1951
2317
  -size * aspect,
1952
2318
  size * aspect,
1953
2319
  size,
@@ -1956,11 +2322,11 @@ function useThree4(options = {}) {
1956
2322
  1e3
1957
2323
  );
1958
2324
  } else {
1959
- camera = new THREE10__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
2325
+ camera = new THREE11__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
1960
2326
  }
1961
2327
  camera.position.copy(initialCameraPosition);
1962
2328
  cameraRef.current = camera;
1963
- const renderer = new THREE10__namespace.WebGLRenderer({
2329
+ const renderer = new THREE11__namespace.WebGLRenderer({
1964
2330
  antialias: true,
1965
2331
  alpha: true,
1966
2332
  canvas: canvasRef.current || void 0
@@ -1968,7 +2334,7 @@ function useThree4(options = {}) {
1968
2334
  renderer.setSize(clientWidth, clientHeight);
1969
2335
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
1970
2336
  renderer.shadowMap.enabled = opts.shadows;
1971
- renderer.shadowMap.type = THREE10__namespace.PCFSoftShadowMap;
2337
+ renderer.shadowMap.type = THREE11__namespace.PCFSoftShadowMap;
1972
2338
  rendererRef.current = renderer;
1973
2339
  const controls = new OrbitControls_js.OrbitControls(camera, renderer.domElement);
1974
2340
  controls.enableDamping = true;
@@ -1977,16 +2343,16 @@ function useThree4(options = {}) {
1977
2343
  controls.maxDistance = 100;
1978
2344
  controls.maxPolarAngle = Math.PI / 2 - 0.1;
1979
2345
  controlsRef.current = controls;
1980
- const ambientLight = new THREE10__namespace.AmbientLight(16777215, 0.6);
2346
+ const ambientLight = new THREE11__namespace.AmbientLight(16777215, 0.6);
1981
2347
  scene.add(ambientLight);
1982
- const directionalLight = new THREE10__namespace.DirectionalLight(16777215, 0.8);
2348
+ const directionalLight = new THREE11__namespace.DirectionalLight(16777215, 0.8);
1983
2349
  directionalLight.position.set(10, 20, 10);
1984
2350
  directionalLight.castShadow = opts.shadows;
1985
2351
  directionalLight.shadow.mapSize.width = 2048;
1986
2352
  directionalLight.shadow.mapSize.height = 2048;
1987
2353
  scene.add(directionalLight);
1988
2354
  if (opts.showGrid) {
1989
- const gridHelper = new THREE10__namespace.GridHelper(
2355
+ const gridHelper = new THREE11__namespace.GridHelper(
1990
2356
  opts.gridSize,
1991
2357
  opts.gridSize,
1992
2358
  4473924,
@@ -2004,10 +2370,10 @@ function useThree4(options = {}) {
2004
2370
  const handleResize = () => {
2005
2371
  const { clientWidth: width, clientHeight: height } = container;
2006
2372
  setDimensions({ width, height });
2007
- if (camera instanceof THREE10__namespace.PerspectiveCamera) {
2373
+ if (camera instanceof THREE11__namespace.PerspectiveCamera) {
2008
2374
  camera.aspect = width / height;
2009
2375
  camera.updateProjectionMatrix();
2010
- } else if (camera instanceof THREE10__namespace.OrthographicCamera) {
2376
+ } else if (camera instanceof THREE11__namespace.OrthographicCamera) {
2011
2377
  const aspect2 = width / height;
2012
2378
  const size = 10;
2013
2379
  camera.left = -size * aspect2;
@@ -2038,7 +2404,7 @@ function useThree4(options = {}) {
2038
2404
  let newCamera;
2039
2405
  if (opts.cameraMode === "isometric") {
2040
2406
  const size = 10;
2041
- newCamera = new THREE10__namespace.OrthographicCamera(
2407
+ newCamera = new THREE11__namespace.OrthographicCamera(
2042
2408
  -size * aspect,
2043
2409
  size * aspect,
2044
2410
  size,
@@ -2047,7 +2413,7 @@ function useThree4(options = {}) {
2047
2413
  1e3
2048
2414
  );
2049
2415
  } else {
2050
- newCamera = new THREE10__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
2416
+ newCamera = new THREE11__namespace.PerspectiveCamera(45, aspect, 0.1, 1e3);
2051
2417
  }
2052
2418
  newCamera.position.copy(currentPos);
2053
2419
  cameraRef.current = newCamera;
@@ -2377,8 +2743,8 @@ function useSceneGraph() {
2377
2743
  }
2378
2744
  function useRaycaster(options) {
2379
2745
  const { camera, canvas, cellSize = 1, offsetX = 0, offsetZ = 0 } = options;
2380
- const raycaster = React3.useRef(new THREE10__namespace.Raycaster());
2381
- 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());
2382
2748
  const clientToNDC = React3.useCallback(
2383
2749
  (clientX, clientY) => {
2384
2750
  if (!canvas) {
@@ -2448,8 +2814,8 @@ function useRaycaster(options) {
2448
2814
  const ndc = clientToNDC(clientX, clientY);
2449
2815
  mouse.current.set(ndc.x, ndc.y);
2450
2816
  raycaster.current.setFromCamera(mouse.current, camera);
2451
- const plane = new THREE10__namespace.Plane(new THREE10__namespace.Vector3(0, 1, 0), 0);
2452
- 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();
2453
2819
  const intersection = raycaster.current.ray.intersectPlane(plane, target);
2454
2820
  if (intersection) {
2455
2821
  const gridX = Math.round((target.x - offsetX) / cellSize);
@@ -2487,7 +2853,7 @@ function useRaycaster(options) {
2487
2853
  return {
2488
2854
  gridX: gridCoords.x,
2489
2855
  gridZ: gridCoords.z,
2490
- worldPosition: new THREE10__namespace.Vector3(
2856
+ worldPosition: new THREE11__namespace.Vector3(
2491
2857
  gridCoords.x * cellSize + offsetX,
2492
2858
  0,
2493
2859
  gridCoords.z * cellSize + offsetZ
@@ -2517,7 +2883,7 @@ var DEFAULT_CONFIG = {
2517
2883
  };
2518
2884
  function gridToWorld(gridX, gridZ, config = DEFAULT_CONFIG) {
2519
2885
  const opts = { ...DEFAULT_CONFIG, ...config };
2520
- return new THREE10__namespace.Vector3(
2886
+ return new THREE11__namespace.Vector3(
2521
2887
  gridX * opts.cellSize + opts.offsetX,
2522
2888
  opts.elevation,
2523
2889
  gridZ * opts.cellSize + opts.offsetZ
@@ -2531,17 +2897,17 @@ function worldToGrid(worldX, worldZ, config = DEFAULT_CONFIG) {
2531
2897
  };
2532
2898
  }
2533
2899
  function raycastToPlane(camera, mouseX, mouseY, planeY = 0) {
2534
- const raycaster = new THREE10__namespace.Raycaster();
2535
- const mouse = new THREE10__namespace.Vector2(mouseX, mouseY);
2900
+ const raycaster = new THREE11__namespace.Raycaster();
2901
+ const mouse = new THREE11__namespace.Vector2(mouseX, mouseY);
2536
2902
  raycaster.setFromCamera(mouse, camera);
2537
- const plane = new THREE10__namespace.Plane(new THREE10__namespace.Vector3(0, 1, 0), -planeY);
2538
- 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();
2539
2905
  const intersection = raycaster.ray.intersectPlane(plane, target);
2540
2906
  return intersection ? target : null;
2541
2907
  }
2542
2908
  function raycastToObjects(camera, mouseX, mouseY, objects) {
2543
- const raycaster = new THREE10__namespace.Raycaster();
2544
- const mouse = new THREE10__namespace.Vector2(mouseX, mouseY);
2909
+ const raycaster = new THREE11__namespace.Raycaster();
2910
+ const mouse = new THREE11__namespace.Vector2(mouseX, mouseY);
2545
2911
  raycaster.setFromCamera(mouse, camera);
2546
2912
  const intersects = raycaster.intersectObjects(objects, true);
2547
2913
  return intersects.length > 0 ? intersects[0] : null;
@@ -2593,14 +2959,14 @@ function getCellsInRadius(centerX, centerZ, radius) {
2593
2959
  return cells;
2594
2960
  }
2595
2961
  function createGridHighlight(color = 16776960, opacity = 0.3) {
2596
- const geometry = new THREE10__namespace.PlaneGeometry(0.95, 0.95);
2597
- const material = new THREE10__namespace.MeshBasicMaterial({
2962
+ const geometry = new THREE11__namespace.PlaneGeometry(0.95, 0.95);
2963
+ const material = new THREE11__namespace.MeshBasicMaterial({
2598
2964
  color,
2599
2965
  transparent: true,
2600
2966
  opacity,
2601
- side: THREE10__namespace.DoubleSide
2967
+ side: THREE11__namespace.DoubleSide
2602
2968
  });
2603
- const mesh = new THREE10__namespace.Mesh(geometry, material);
2969
+ const mesh = new THREE11__namespace.Mesh(geometry, material);
2604
2970
  mesh.rotation.x = -Math.PI / 2;
2605
2971
  mesh.position.y = 0.01;
2606
2972
  return mesh;
@@ -2613,31 +2979,31 @@ function normalizeMouseCoordinates(clientX, clientY, element) {
2613
2979
  };
2614
2980
  }
2615
2981
  function isInFrustum(position, camera, padding = 0) {
2616
- const frustum = new THREE10__namespace.Frustum();
2617
- const projScreenMatrix = new THREE10__namespace.Matrix4();
2982
+ const frustum = new THREE11__namespace.Frustum();
2983
+ const projScreenMatrix = new THREE11__namespace.Matrix4();
2618
2984
  projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
2619
2985
  frustum.setFromProjectionMatrix(projScreenMatrix);
2620
- const sphere = new THREE10__namespace.Sphere(position, padding);
2986
+ const sphere = new THREE11__namespace.Sphere(position, padding);
2621
2987
  return frustum.intersectsSphere(sphere);
2622
2988
  }
2623
2989
  function filterByFrustum(positions, camera, padding = 0) {
2624
- const frustum = new THREE10__namespace.Frustum();
2625
- const projScreenMatrix = new THREE10__namespace.Matrix4();
2990
+ const frustum = new THREE11__namespace.Frustum();
2991
+ const projScreenMatrix = new THREE11__namespace.Matrix4();
2626
2992
  projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
2627
2993
  frustum.setFromProjectionMatrix(projScreenMatrix);
2628
2994
  return positions.filter((position) => {
2629
- const sphere = new THREE10__namespace.Sphere(position, padding);
2995
+ const sphere = new THREE11__namespace.Sphere(position, padding);
2630
2996
  return frustum.intersectsSphere(sphere);
2631
2997
  });
2632
2998
  }
2633
2999
  function getVisibleIndices(positions, camera, padding = 0) {
2634
- const frustum = new THREE10__namespace.Frustum();
2635
- const projScreenMatrix = new THREE10__namespace.Matrix4();
3000
+ const frustum = new THREE11__namespace.Frustum();
3001
+ const projScreenMatrix = new THREE11__namespace.Matrix4();
2636
3002
  const visible = /* @__PURE__ */ new Set();
2637
3003
  projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
2638
3004
  frustum.setFromProjectionMatrix(projScreenMatrix);
2639
3005
  positions.forEach((position, index) => {
2640
- const sphere = new THREE10__namespace.Sphere(position, padding);
3006
+ const sphere = new THREE11__namespace.Sphere(position, padding);
2641
3007
  if (frustum.intersectsSphere(sphere)) {
2642
3008
  visible.add(index);
2643
3009
  }
@@ -2661,7 +3027,7 @@ function updateInstanceLOD(instancedMesh, positions, camera, lodDistances) {
2661
3027
  return lodIndices;
2662
3028
  }
2663
3029
  function cullInstancedMesh(instancedMesh, positions, visibleIndices) {
2664
- const dummy = new THREE10__namespace.Object3D();
3030
+ const dummy = new THREE11__namespace.Object3D();
2665
3031
  let visibleCount = 0;
2666
3032
  positions.forEach((position, index) => {
2667
3033
  if (visibleIndices.has(index)) {
@@ -3828,25 +4194,25 @@ function orbitRingPositions(count, radius, tilt) {
3828
4194
  return positions;
3829
4195
  }
3830
4196
  function arcCurve3D(from, to, offset) {
3831
- const start = new THREE10.Vector3(...from);
3832
- const end = new THREE10.Vector3(...to);
3833
- const mid = new THREE10.Vector3().addVectors(start, end).multiplyScalar(0.5);
3834
- const dir = new THREE10.Vector3().subVectors(end, start).normalize();
3835
- const up = new THREE10.Vector3(0, 1, 0);
3836
- 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();
3837
4203
  if (perp.length() < 1e-3) {
3838
- perp.crossVectors(dir, new THREE10.Vector3(1, 0, 0)).normalize();
4204
+ perp.crossVectors(dir, new THREE11.Vector3(1, 0, 0)).normalize();
3839
4205
  }
3840
4206
  const control = mid.clone().add(perp.multiplyScalar(offset));
3841
4207
  control.y += Math.abs(offset) * 0.3;
3842
- return new THREE10.QuadraticBezierCurve3(start, control, end);
4208
+ return new THREE11.QuadraticBezierCurve3(start, control, end);
3843
4209
  }
3844
4210
  function selfLoopCurve3D(position, loopRadius) {
3845
- const base = new THREE10.Vector3(...position);
3846
- const start = base.clone().add(new THREE10.Vector3(-loopRadius * 0.3, 0, 0));
3847
- const end = base.clone().add(new THREE10.Vector3(loopRadius * 0.3, 0, 0));
3848
- const control = base.clone().add(new THREE10.Vector3(0, loopRadius, 0));
3849
- 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);
3850
4216
  }
3851
4217
  function treeLayout3D(node, origin, horizontalSpacing, verticalSpacing = 2) {
3852
4218
  const results = [];
@@ -4013,7 +4379,7 @@ var Avl3DOrbitalNode = ({
4013
4379
  if (!groupRef.current) return;
4014
4380
  groupRef.current.rotation.y += delta * (hovered ? 0.4 : 0.2);
4015
4381
  groupRef.current.rotation.x += delta * 0.05;
4016
- currentScale.current = THREE10.MathUtils.damp(currentScale.current, targetScale, 6, delta);
4382
+ currentScale.current = THREE11.MathUtils.damp(currentScale.current, targetScale, 6, delta);
4017
4383
  });
4018
4384
  const baseBrightness = 0.3 + Math.min(pageCount, 5) * 0.05;
4019
4385
  const emissiveIntensity = hovered ? 0.8 : baseBrightness;
@@ -4655,7 +5021,7 @@ var Avl3DStateNode = ({
4655
5021
  const targetScale = hovered ? 1.08 : 1;
4656
5022
  const currentScale = React3.useRef(1);
4657
5023
  fiber.useFrame((_, delta) => {
4658
- currentScale.current = THREE10.MathUtils.damp(currentScale.current, targetScale, 6, delta);
5024
+ currentScale.current = THREE11.MathUtils.damp(currentScale.current, targetScale, 6, delta);
4659
5025
  });
4660
5026
  const scale = currentScale.current;
4661
5027
  return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
@@ -4835,9 +5201,9 @@ var Avl3DTransitionArc = ({
4835
5201
  const guardPt = curve.getPoint(0.3);
4836
5202
  const arrowPt = curve.getPoint(0.9);
4837
5203
  const arrowTangent = curve.getTangent(0.9);
4838
- const upVec = new THREE10.Vector3(0, 1, 0);
4839
- const tangentVec = new THREE10.Vector3(arrowTangent.x, arrowTangent.y, arrowTangent.z).normalize();
4840
- 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);
4841
5207
  const effectPositions2 = [];
4842
5208
  for (let ei = 0; ei < 4; ei++) {
4843
5209
  const t = 0.7 + ei * 0.05;
@@ -5061,14 +5427,14 @@ function operatorColor(label) {
5061
5427
  return "#4A90D9";
5062
5428
  }
5063
5429
  function edgeGeometry(parent, child) {
5064
- const p = new THREE10.Vector3(parent.x, parent.y, parent.z);
5065
- const c = new THREE10.Vector3(child.x, child.y, child.z);
5066
- const mid = new THREE10.Vector3().addVectors(p, c).multiplyScalar(0.5);
5067
- 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);
5068
5434
  const length = dir.length();
5069
- const yAxis = new THREE10.Vector3(0, 1, 0);
5435
+ const yAxis = new THREE11.Vector3(0, 1, 0);
5070
5436
  const angle = yAxis.angleTo(dir.normalize());
5071
- const axis = new THREE10.Vector3().crossVectors(yAxis, dir).normalize();
5437
+ const axis = new THREE11.Vector3().crossVectors(yAxis, dir).normalize();
5072
5438
  if (axis.length() < 1e-3) {
5073
5439
  return {
5074
5440
  position: [mid.x, mid.y, mid.z],
@@ -5444,12 +5810,12 @@ function useAvl3DConfig() {
5444
5810
  }
5445
5811
  function CameraController({ targetPosition, targetLookAt, animated }) {
5446
5812
  const { camera } = fiber.useThree();
5447
- const targetPosVec = React3.useRef(new THREE10__namespace.Vector3(...targetPosition));
5448
- 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));
5449
5815
  const isAnimating = React3.useRef(false);
5450
5816
  React3.useEffect(() => {
5451
- const newTarget = new THREE10__namespace.Vector3(...targetPosition);
5452
- const newLookAt = new THREE10__namespace.Vector3(...targetLookAt);
5817
+ const newTarget = new THREE11__namespace.Vector3(...targetPosition);
5818
+ const newLookAt = new THREE11__namespace.Vector3(...targetLookAt);
5453
5819
  if (!newTarget.equals(targetPosVec.current) || !newLookAt.equals(targetLookVec.current)) {
5454
5820
  targetPosVec.current.copy(newTarget);
5455
5821
  targetLookVec.current.copy(newLookAt);
@@ -5464,9 +5830,9 @@ function CameraController({ targetPosition, targetLookAt, animated }) {
5464
5830
  fiber.useFrame((_, delta) => {
5465
5831
  if (!isAnimating.current) return;
5466
5832
  const speed = 3;
5467
- camera.position.x = THREE10__namespace.MathUtils.damp(camera.position.x, targetPosVec.current.x, speed, delta);
5468
- camera.position.y = THREE10__namespace.MathUtils.damp(camera.position.y, targetPosVec.current.y, speed, delta);
5469
- 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);
5470
5836
  camera.lookAt(targetLookVec.current);
5471
5837
  const dist = camera.position.distanceTo(targetPosVec.current);
5472
5838
  if (dist < 0.05) {
@@ -5481,7 +5847,7 @@ function SceneFade({ animating, children }) {
5481
5847
  fiber.useFrame((_, delta) => {
5482
5848
  if (!groupRef.current) return;
5483
5849
  const target = animating ? 0 : 1;
5484
- opacityRef.current = THREE10__namespace.MathUtils.damp(opacityRef.current, target, 5, delta);
5850
+ opacityRef.current = THREE11__namespace.MathUtils.damp(opacityRef.current, target, 5, delta);
5485
5851
  groupRef.current.visible = opacityRef.current > 0.05;
5486
5852
  const s = 0.9 + opacityRef.current * 0.1;
5487
5853
  groupRef.current.scale.setScalar(s);
@@ -5781,5 +6147,5 @@ exports.useAvl3DConfig = useAvl3DConfig;
5781
6147
  exports.useGameCanvas3DEvents = useGameCanvas3DEvents;
5782
6148
  exports.useRaycaster = useRaycaster;
5783
6149
  exports.useSceneGraph = useSceneGraph;
5784
- exports.useThree = useThree4;
6150
+ exports.useThree = useThree5;
5785
6151
  exports.worldToGrid = worldToGrid;