@almadar/ui 2.16.0 → 2.17.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.
@@ -19,12 +19,6 @@ require('leaflet/dist/leaflet.css');
19
19
  var context = require('@almadar/ui/context');
20
20
  var patterns = require('@almadar/patterns');
21
21
  var reactRouterDom = require('react-router-dom');
22
- var fiber = require('@react-three/fiber');
23
- var drei = require('@react-three/drei');
24
- var THREE = require('three');
25
- var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
26
- var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
27
- var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
28
22
  var reactQuery = require('@tanstack/react-query');
29
23
 
30
24
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -56,7 +50,6 @@ var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
56
50
  var SyntaxHighlighter__default = /*#__PURE__*/_interopDefault(SyntaxHighlighter);
57
51
  var dark__default = /*#__PURE__*/_interopDefault(dark);
58
52
  var L__default = /*#__PURE__*/_interopDefault(L);
59
- var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
60
53
 
61
54
  var __defProp = Object.defineProperty;
62
55
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -1057,7 +1050,7 @@ var Box = React87__namespace.default.forwardRef(
1057
1050
  position,
1058
1051
  className,
1059
1052
  children,
1060
- as: Component2 = "div",
1053
+ as: Component = "div",
1061
1054
  action,
1062
1055
  actionPayload,
1063
1056
  hoverEvent,
@@ -1087,7 +1080,7 @@ var Box = React87__namespace.default.forwardRef(
1087
1080
  onMouseLeave?.(e);
1088
1081
  }, [hoverEvent, eventBus, onMouseLeave]);
1089
1082
  const isClickable = action || onClick;
1090
- const Comp = Component2;
1083
+ const Comp = Component;
1091
1084
  return /* @__PURE__ */ jsxRuntime.jsx(
1092
1085
  Comp,
1093
1086
  {
@@ -1142,10 +1135,10 @@ var Center = ({
1142
1135
  className,
1143
1136
  style,
1144
1137
  children,
1145
- as: Component2 = "div"
1138
+ as: Component = "div"
1146
1139
  }) => {
1147
1140
  const mergedStyle = minHeight ? { minHeight, ...style } : style;
1148
- const Comp = Component2;
1141
+ const Comp = Component;
1149
1142
  return /* @__PURE__ */ jsxRuntime.jsx(
1150
1143
  Comp,
1151
1144
  {
@@ -1630,7 +1623,7 @@ var Stack = ({
1630
1623
  className,
1631
1624
  style,
1632
1625
  children,
1633
- as: Component2 = "div",
1626
+ as: Component = "div",
1634
1627
  onClick,
1635
1628
  onKeyDown,
1636
1629
  role,
@@ -1648,7 +1641,7 @@ var Stack = ({
1648
1641
  };
1649
1642
  const isHorizontal = direction === "horizontal";
1650
1643
  const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
1651
- const Comp = Component2;
1644
+ const Comp = Component;
1652
1645
  return /* @__PURE__ */ jsxRuntime.jsx(
1653
1646
  Comp,
1654
1647
  {
@@ -1819,8 +1812,8 @@ var Typography = ({
1819
1812
  children
1820
1813
  }) => {
1821
1814
  const variant = variantProp ?? (level ? `h${level}` : "body1");
1822
- const Component2 = as || defaultElements[variant];
1823
- const Comp = Component2;
1815
+ const Component = as || defaultElements[variant];
1816
+ const Comp = Component;
1824
1817
  return /* @__PURE__ */ jsxRuntime.jsx(
1825
1818
  Comp,
1826
1819
  {
@@ -5659,10 +5652,10 @@ var Container = ({
5659
5652
  center = true,
5660
5653
  className,
5661
5654
  children,
5662
- as: Component2 = "div"
5655
+ as: Component = "div"
5663
5656
  }) => {
5664
5657
  const resolvedSize = maxWidth ?? size ?? "lg";
5665
- const Comp = Component2;
5658
+ const Comp = Component;
5666
5659
  return /* @__PURE__ */ jsxRuntime.jsx(
5667
5660
  Comp,
5668
5661
  {
@@ -5725,7 +5718,7 @@ var Flex = ({
5725
5718
  basis,
5726
5719
  className,
5727
5720
  children,
5728
- as: Component2 = "div"
5721
+ as: Component = "div"
5729
5722
  }) => {
5730
5723
  const flexStyle = {};
5731
5724
  if (grow !== void 0 || shrink !== void 0 || basis !== void 0) {
@@ -5737,7 +5730,7 @@ var Flex = ({
5737
5730
  flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
5738
5731
  }
5739
5732
  }
5740
- const Comp = Component2;
5733
+ const Comp = Component;
5741
5734
  return /* @__PURE__ */ jsxRuntime.jsx(
5742
5735
  Comp,
5743
5736
  {
@@ -5994,10 +5987,10 @@ var Grid = ({
5994
5987
  className,
5995
5988
  style,
5996
5989
  children,
5997
- as: Component2 = "div"
5990
+ as: Component = "div"
5998
5991
  }) => {
5999
5992
  const mergedStyle = rows ? { gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`, ...style } : style;
6000
- const Comp = Component2;
5993
+ const Comp = Component;
6001
5994
  return /* @__PURE__ */ jsxRuntime.jsx(
6002
5995
  Comp,
6003
5996
  {
@@ -17593,10 +17586,10 @@ var Section = ({
17593
17586
  children,
17594
17587
  headerClassName,
17595
17588
  contentClassName,
17596
- as: Component2 = "section"
17589
+ as: Component = "section"
17597
17590
  }) => {
17598
17591
  const hasHeader = title || description || action;
17599
- const Comp = Component2;
17592
+ const Comp = Component;
17600
17593
  return /* @__PURE__ */ jsxRuntime.jsxs(
17601
17594
  Comp,
17602
17595
  {
@@ -28369,216 +28362,6 @@ function DividerPattern({
28369
28362
  );
28370
28363
  }
28371
28364
  DividerPattern.displayName = "DividerPattern";
28372
- var Camera3D = React87.forwardRef(
28373
- ({
28374
- mode = "isometric",
28375
- position = [10, 10, 10],
28376
- target = [0, 0, 0],
28377
- zoom = 1,
28378
- fov = 45,
28379
- enableOrbit = true,
28380
- minDistance = 2,
28381
- maxDistance = 100,
28382
- onChange
28383
- }, ref) => {
28384
- const { camera, set, viewport } = fiber.useThree();
28385
- const controlsRef = React87.useRef(null);
28386
- const initialPosition = React87.useRef(new THREE__namespace.Vector3(...position));
28387
- const initialTarget = React87.useRef(new THREE__namespace.Vector3(...target));
28388
- React87.useEffect(() => {
28389
- let newCamera;
28390
- if (mode === "isometric") {
28391
- const aspect = viewport.aspect;
28392
- const size = 10 / zoom;
28393
- newCamera = new THREE__namespace.OrthographicCamera(
28394
- -size * aspect,
28395
- size * aspect,
28396
- size,
28397
- -size,
28398
- 0.1,
28399
- 1e3
28400
- );
28401
- } else {
28402
- newCamera = new THREE__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
28403
- }
28404
- newCamera.position.copy(initialPosition.current);
28405
- newCamera.lookAt(initialTarget.current);
28406
- set({ camera: newCamera });
28407
- if (mode === "top-down") {
28408
- newCamera.position.set(0, 20 / zoom, 0);
28409
- newCamera.lookAt(0, 0, 0);
28410
- }
28411
- return () => {
28412
- };
28413
- }, [mode, fov, zoom, viewport.aspect, set]);
28414
- fiber.useFrame(() => {
28415
- if (onChange) {
28416
- onChange(camera);
28417
- }
28418
- });
28419
- React87.useImperativeHandle(ref, () => ({
28420
- getCamera: () => camera,
28421
- setPosition: (x, y, z) => {
28422
- camera.position.set(x, y, z);
28423
- if (controlsRef.current) {
28424
- controlsRef.current.update();
28425
- }
28426
- },
28427
- lookAt: (x, y, z) => {
28428
- camera.lookAt(x, y, z);
28429
- if (controlsRef.current) {
28430
- controlsRef.current.target.set(x, y, z);
28431
- controlsRef.current.update();
28432
- }
28433
- },
28434
- reset: () => {
28435
- camera.position.copy(initialPosition.current);
28436
- camera.lookAt(initialTarget.current);
28437
- if (controlsRef.current) {
28438
- controlsRef.current.target.copy(initialTarget.current);
28439
- controlsRef.current.update();
28440
- }
28441
- },
28442
- getViewBounds: () => {
28443
- const min = new THREE__namespace.Vector3(-10, -10, -10);
28444
- const max = new THREE__namespace.Vector3(10, 10, 10);
28445
- return { min, max };
28446
- }
28447
- }));
28448
- const maxPolarAngle = mode === "top-down" ? 0.1 : Math.PI / 2 - 0.1;
28449
- return /* @__PURE__ */ jsxRuntime.jsx(
28450
- drei.OrbitControls,
28451
- {
28452
- ref: controlsRef,
28453
- camera,
28454
- enabled: enableOrbit,
28455
- target: initialTarget.current,
28456
- minDistance,
28457
- maxDistance,
28458
- maxPolarAngle,
28459
- enableDamping: true,
28460
- dampingFactor: 0.05
28461
- }
28462
- );
28463
- }
28464
- );
28465
- Camera3D.displayName = "Camera3D";
28466
- var Canvas3DErrorBoundary = class extends React87.Component {
28467
- constructor(props) {
28468
- super(props);
28469
- __publicField(this, "handleReset", () => {
28470
- this.setState({
28471
- hasError: false,
28472
- error: null,
28473
- errorInfo: null
28474
- });
28475
- this.props.onReset?.();
28476
- });
28477
- this.state = {
28478
- hasError: false,
28479
- error: null,
28480
- errorInfo: null
28481
- };
28482
- }
28483
- static getDerivedStateFromError(error) {
28484
- return {
28485
- hasError: true,
28486
- error,
28487
- errorInfo: null
28488
- };
28489
- }
28490
- componentDidCatch(error, errorInfo) {
28491
- this.setState({ errorInfo });
28492
- this.props.onError?.(error, errorInfo);
28493
- console.error("[Canvas3DErrorBoundary] Error caught:", error);
28494
- console.error("[Canvas3DErrorBoundary] Component stack:", errorInfo.componentStack);
28495
- }
28496
- render() {
28497
- if (this.state.hasError) {
28498
- if (this.props.fallback) {
28499
- return this.props.fallback;
28500
- }
28501
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__content", children: [
28502
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
28503
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
28504
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
28505
- this.state.error && /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "canvas-3d-error__details", children: [
28506
- /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Error Details" }),
28507
- /* @__PURE__ */ jsxRuntime.jsxs("pre", { className: "error__stack", children: [
28508
- this.state.error.message,
28509
- "\n",
28510
- this.state.error.stack
28511
- ] }),
28512
- this.state.errorInfo && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
28513
- ] }),
28514
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__actions", children: [
28515
- /* @__PURE__ */ jsxRuntime.jsx(
28516
- "button",
28517
- {
28518
- className: "error__button error__button--primary",
28519
- onClick: this.handleReset,
28520
- children: "Try Again"
28521
- }
28522
- ),
28523
- /* @__PURE__ */ jsxRuntime.jsx(
28524
- "button",
28525
- {
28526
- className: "error__button error__button--secondary",
28527
- onClick: () => window.location.reload(),
28528
- children: "Reload Page"
28529
- }
28530
- )
28531
- ] })
28532
- ] }) });
28533
- }
28534
- return this.props.children;
28535
- }
28536
- };
28537
- function Canvas3DLoadingState({
28538
- progress = 0,
28539
- loaded = 0,
28540
- total = 0,
28541
- message = "Loading 3D Scene...",
28542
- details,
28543
- showSpinner = true,
28544
- className
28545
- }) {
28546
- const clampedProgress = Math.max(0, Math.min(100, progress));
28547
- const hasProgress = total > 0;
28548
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
28549
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__content", children: [
28550
- showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__spinner", children: [
28551
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring" }),
28552
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring spinner__ring--secondary" })
28553
- ] }),
28554
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__message", children: message }),
28555
- details && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__details", children: details }),
28556
- hasProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__progress", children: [
28557
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsxRuntime.jsx(
28558
- "div",
28559
- {
28560
- className: "progress__fill",
28561
- style: { width: `${clampedProgress}%` }
28562
- }
28563
- ) }),
28564
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "progress__text", children: [
28565
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__percentage", children: [
28566
- clampedProgress,
28567
- "%"
28568
- ] }),
28569
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__count", children: [
28570
- "(",
28571
- loaded,
28572
- "/",
28573
- total,
28574
- ")"
28575
- ] })
28576
- ] })
28577
- ] })
28578
- ] }),
28579
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg__grid" }) })
28580
- ] });
28581
- }
28582
28365
  function CastleTemplate({
28583
28366
  entity,
28584
28367
  scale = 0.45,
@@ -29939,1771 +29722,113 @@ var DocumentViewer = ({
29939
29722
  );
29940
29723
  }
29941
29724
  return /* @__PURE__ */ jsxRuntime.jsx(
29942
- Box,
29943
- {
29944
- className: "w-full overflow-auto p-4 font-mono text-sm",
29945
- style: { height, fontSize: `${zoom}%` },
29946
- children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: activeContent })
29947
- }
29948
- );
29949
- };
29950
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
29951
- tabItems && tabItems.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsxRuntime.jsx(
29952
- Tabs,
29953
- {
29954
- tabs: tabItems,
29955
- activeTab: `doc-${activeDocIndex}`,
29956
- onTabChange: (id) => {
29957
- const idx = parseInt(id.replace("doc-", ""), 10);
29958
- setActiveDocIndex(idx);
29959
- }
29960
- }
29961
- ) }),
29962
- showToolbar && /* @__PURE__ */ jsxRuntime.jsxs(
29963
- HStack,
29964
- {
29965
- gap: "sm",
29966
- align: "center",
29967
- justify: "between",
29968
- className: "px-4 py-2 border-b border-[var(--color-border)] bg-[var(--color-muted)]/30",
29969
- children: [
29970
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", children: [
29971
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons.FileText, size: "sm", className: "text-[var(--color-muted-foreground)]" }),
29972
- title && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "truncate max-w-[200px]", children: title })
29973
- ] }),
29974
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
29975
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ZoomOut, onClick: handleZoomOut }),
29976
- /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", color: "secondary", className: "tabular-nums w-10 text-center", children: [
29977
- zoom,
29978
- "%"
29979
- ] }),
29980
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ZoomIn, onClick: handleZoomIn }),
29981
- totalPages && totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29982
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-px h-4 bg-[var(--color-border)] mx-1" }),
29983
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ChevronLeft, onClick: handlePagePrev, disabled: currentPage <= 1 }),
29984
- /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: [
29985
- currentPage,
29986
- " / ",
29987
- totalPages
29988
- ] }),
29989
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ChevronRight, onClick: handlePageNext, disabled: currentPage >= totalPages })
29990
- ] }),
29991
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-px h-4 bg-[var(--color-border)] mx-1" }),
29992
- showDownload && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.Download, onClick: handleDownload }),
29993
- showPrint && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.Printer, onClick: handlePrint }),
29994
- actions?.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
29995
- Badge,
29996
- {
29997
- variant: "default",
29998
- className: "cursor-pointer hover:opacity-80 transition-opacity",
29999
- onClick: () => handleAction(action),
30000
- children: action.label
30001
- },
30002
- idx
30003
- ))
30004
- ] })
30005
- ]
30006
- }
30007
- ),
30008
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full overflow-hidden bg-[var(--color-muted)]/20", children: renderContent() })
30009
- ] }) });
30010
- };
30011
- DocumentViewer.displayName = "DocumentViewer";
30012
- function extractTitle(children) {
30013
- if (!React87__namespace.default.isValidElement(children)) return void 0;
30014
- const props = children.props;
30015
- if (typeof props.title === "string") {
30016
- return props.title;
30017
- }
30018
- return void 0;
30019
- }
30020
- var DrawerSlot = ({
30021
- children,
30022
- title: overrideTitle,
30023
- position = "right",
30024
- size = "md",
30025
- className
30026
- }) => {
30027
- const eventBus = useEventBus();
30028
- const isOpen = Boolean(children);
30029
- const title = overrideTitle || extractTitle(children);
30030
- const handleClose = () => {
30031
- eventBus.emit("UI:CLOSE");
30032
- eventBus.emit("UI:CANCEL");
30033
- };
30034
- if (!isOpen) return null;
30035
- return /* @__PURE__ */ jsxRuntime.jsx(
30036
- Drawer,
30037
- {
30038
- isOpen,
30039
- onClose: handleClose,
30040
- title,
30041
- position,
30042
- width: size,
30043
- className,
30044
- children
30045
- }
30046
- );
30047
- };
30048
- DrawerSlot.displayName = "DrawerSlot";
30049
- var DEFAULT_FEATURE_CONFIGS = {
30050
- tree: { color: 2263842, height: 1.5, scale: 1, geometry: "tree" },
30051
- rock: { color: 8421504, height: 0.5, scale: 0.8, geometry: "rock" },
30052
- bush: { color: 3329330, height: 0.4, scale: 0.6, geometry: "bush" },
30053
- house: { color: 9127187, height: 1.2, scale: 1.2, geometry: "house" },
30054
- tower: { color: 6908265, height: 2.5, scale: 1, geometry: "tower" },
30055
- wall: { color: 8421504, height: 1, scale: 1, geometry: "wall" },
30056
- mountain: { color: 5597999, height: 2, scale: 1.5, geometry: "mountain" },
30057
- hill: { color: 7048739, height: 0.8, scale: 1.2, geometry: "hill" },
30058
- water: { color: 4491468, height: 0.1, scale: 1, geometry: "water" },
30059
- chest: { color: 16766720, height: 0.3, scale: 0.4, geometry: "chest" },
30060
- sign: { color: 9127187, height: 0.8, scale: 0.3, geometry: "sign" },
30061
- portal: { color: 10040012, height: 1.5, scale: 1, geometry: "portal" }
30062
- };
30063
- function TreeFeature({ height, color }) {
30064
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
30065
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.3, 0], children: [
30066
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.08, 0.1, height * 0.6, 6] }),
30067
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 9127187 })
30068
- ] }),
30069
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.7, 0], children: [
30070
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.4, height * 0.5, 8] }),
30071
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30072
- ] }),
30073
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.9, 0], children: [
30074
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.3, height * 0.4, 8] }),
30075
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30076
- ] }),
30077
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 1.05, 0], children: [
30078
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.15, height * 0.25, 8] }),
30079
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30080
- ] })
30081
- ] });
30082
- }
30083
- function RockFeature({ height, color }) {
30084
- return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.4, 0], children: [
30085
- /* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [height * 0.5, 0] }),
30086
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, roughness: 0.9 })
30087
- ] });
30088
- }
30089
- function BushFeature({ height, color }) {
30090
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
30091
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.3, 0], children: [
30092
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [height * 0.4, 8, 8] }),
30093
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30094
- ] }),
30095
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0.1, height * 0.4, 0.1], children: [
30096
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [height * 0.25, 8, 8] }),
30097
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30098
- ] })
30099
- ] });
30100
- }
30101
- function HouseFeature({ height, color }) {
30102
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
30103
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.4, 0], children: [
30104
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.8, height * 0.8, 0.8] }),
30105
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 13808780 })
30106
- ] }),
30107
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.9, 0], children: [
30108
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.6, height * 0.4, 4] }),
30109
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30110
- ] }),
30111
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.25, 0.41], children: [
30112
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.25, height * 0.5] }),
30113
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 4863784 })
30114
- ] })
30115
- ] });
30116
- }
30117
- function TowerFeature({ height, color }) {
30118
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
30119
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.5, 0], children: [
30120
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.35, height, 8] }),
30121
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30122
- ] }),
30123
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height + 0.05, 0], children: [
30124
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.35, 0.35, 0.1, 8] }),
30125
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30126
- ] })
30127
- ] });
30128
- }
30129
- function ChestFeature({ height, color }) {
30130
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
30131
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.5, 0], children: [
30132
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.3, height, 0.2] }),
30133
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, metalness: 0.6, roughness: 0.3 })
30134
- ] }),
30135
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height + 0.05, 0], children: [
30136
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.15, 0.15, 0.3, 8, 1, false, 0, Math.PI] }),
30137
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, metalness: 0.6, roughness: 0.3 })
30138
- ] })
30139
- ] });
30140
- }
30141
- function DefaultFeature({ height, color }) {
30142
- return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.5, 0], children: [
30143
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.5, height, 0.5] }),
30144
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
30145
- ] });
30146
- }
30147
- function FeatureVisual({
30148
- feature,
30149
- position,
30150
- isSelected,
30151
- onClick,
30152
- onHover
30153
- }) {
30154
- const config = DEFAULT_FEATURE_CONFIGS[feature.type] || {
30155
- color: 8947848,
30156
- height: 0.5,
30157
- scale: 1,
30158
- geometry: "default"
30159
- };
30160
- const color = feature.color ? parseInt(feature.color.replace("#", ""), 16) : config.color;
30161
- const renderGeometry = () => {
30162
- switch (config.geometry) {
30163
- case "tree":
30164
- return /* @__PURE__ */ jsxRuntime.jsx(TreeFeature, { height: config.height, color });
30165
- case "rock":
30166
- return /* @__PURE__ */ jsxRuntime.jsx(RockFeature, { height: config.height, color });
30167
- case "bush":
30168
- return /* @__PURE__ */ jsxRuntime.jsx(BushFeature, { height: config.height, color });
30169
- case "house":
30170
- return /* @__PURE__ */ jsxRuntime.jsx(HouseFeature, { height: config.height, color });
30171
- case "tower":
30172
- return /* @__PURE__ */ jsxRuntime.jsx(TowerFeature, { height: config.height, color });
30173
- case "chest":
30174
- return /* @__PURE__ */ jsxRuntime.jsx(ChestFeature, { height: config.height, color });
30175
- default:
30176
- return /* @__PURE__ */ jsxRuntime.jsx(DefaultFeature, { height: config.height, color });
30177
- }
30178
- };
30179
- return /* @__PURE__ */ jsxRuntime.jsxs(
30180
- "group",
30181
- {
30182
- position,
30183
- scale: config.scale,
30184
- onClick,
30185
- onPointerEnter: () => onHover(true),
30186
- onPointerLeave: () => onHover(false),
30187
- userData: { type: "feature", featureId: feature.id, featureType: feature.type },
30188
- children: [
30189
- isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
30190
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
30191
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
30192
- ] }),
30193
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.01, 0], rotation: [-Math.PI / 2, 0, 0], children: [
30194
- /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [0.35, 16] }),
30195
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#000000", transparent: true, opacity: 0.2 })
30196
- ] }),
30197
- renderGeometry()
30198
- ]
30199
- }
30200
- );
30201
- }
30202
- function FeatureRenderer({
30203
- features,
30204
- cellSize = 1,
30205
- offsetX = 0,
30206
- offsetZ = 0,
30207
- onFeatureClick,
30208
- onFeatureHover,
30209
- selectedFeatureIds = [],
30210
- featureColors
30211
- }) {
30212
- return /* @__PURE__ */ jsxRuntime.jsx("group", { children: features.map((feature) => {
30213
- const x = (feature.x - offsetX) * cellSize;
30214
- const z = ((feature.z ?? feature.y ?? 0) - offsetZ) * cellSize;
30215
- const y = (feature.elevation ?? 0) * 0.1;
30216
- const isSelected = feature.id ? selectedFeatureIds.includes(feature.id) : false;
30217
- return /* @__PURE__ */ jsxRuntime.jsx(
30218
- FeatureVisual,
30219
- {
30220
- feature,
30221
- position: [x, y, z],
30222
- isSelected,
30223
- onClick: () => onFeatureClick?.(feature),
30224
- onHover: (hovered) => onFeatureHover?.(hovered ? feature : null)
30225
- },
30226
- feature.id ?? `feature-${feature.x}-${feature.y}`
30227
- );
30228
- }) });
30229
- }
30230
- function detectAssetRoot(modelUrl) {
30231
- const idx = modelUrl.indexOf("/3d/");
30232
- if (idx !== -1) {
30233
- return modelUrl.substring(0, idx + 4);
30234
- }
30235
- return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
30236
- }
30237
- function useGLTFModel(url) {
30238
- const [model, setModel] = React87.useState(null);
30239
- const [isLoading, setIsLoading] = React87.useState(false);
30240
- const [error, setError] = React87.useState(null);
30241
- React87.useEffect(() => {
30242
- if (!url) {
30243
- setModel(null);
30244
- return;
30245
- }
30246
- setIsLoading(true);
30247
- setError(null);
30248
- const assetRoot = detectAssetRoot(url);
30249
- const loader = new GLTFLoader.GLTFLoader();
30250
- loader.setResourcePath(assetRoot);
30251
- loader.load(
30252
- url,
30253
- (gltf) => {
30254
- setModel(gltf.scene);
30255
- setIsLoading(false);
30256
- },
30257
- void 0,
30258
- (err) => {
30259
- setError(err instanceof Error ? err : new Error(String(err)));
30260
- setIsLoading(false);
30261
- }
30262
- );
30263
- }, [url]);
30264
- return { model, isLoading, error };
30265
- }
30266
- function FeatureModel({
30267
- feature,
30268
- position,
30269
- isSelected,
30270
- onClick,
30271
- onHover
30272
- }) {
30273
- const groupRef = React87.useRef(null);
30274
- const { model: loadedModel, isLoading } = useGLTFModel(feature.assetUrl);
30275
- const model = React87.useMemo(() => {
30276
- if (!loadedModel) return null;
30277
- const cloned = loadedModel.clone();
30278
- cloned.scale.setScalar(0.3);
30279
- cloned.traverse((child) => {
30280
- if (child instanceof THREE__namespace.Mesh) {
30281
- child.castShadow = true;
30282
- child.receiveShadow = true;
30283
- }
30284
- });
30285
- return cloned;
30286
- }, [loadedModel]);
30287
- fiber.useFrame((state) => {
30288
- if (groupRef.current) {
30289
- const featureRotation = feature.rotation;
30290
- const baseRotation = featureRotation !== void 0 ? featureRotation * Math.PI / 180 - Math.PI / 4 : -Math.PI / 4;
30291
- const wobble = isSelected ? Math.sin(state.clock.elapsedTime * 2) * 0.1 : 0;
30292
- groupRef.current.rotation.y = baseRotation + wobble;
30293
- }
30294
- });
30295
- if (isLoading) {
30296
- return /* @__PURE__ */ jsxRuntime.jsx("group", { position, children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
30297
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
30298
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
30299
- ] }) });
30300
- }
30301
- if (!model && !feature.assetUrl) {
30302
- return /* @__PURE__ */ jsxRuntime.jsxs(
30303
- "group",
30304
- {
30305
- position,
30306
- onClick,
30307
- onPointerEnter: () => onHover(true),
30308
- onPointerLeave: () => onHover(false),
30309
- userData: { type: "feature", featureId: feature.id, featureType: feature.type },
30310
- children: [
30311
- isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
30312
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
30313
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
30314
- ] }),
30315
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.5, 0], children: [
30316
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.4, 0.4, 0.4] }),
30317
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 8947848 })
30318
- ] })
30319
- ]
30320
- }
30321
- );
30322
- }
30323
- return /* @__PURE__ */ jsxRuntime.jsxs(
30324
- "group",
30325
- {
30326
- ref: groupRef,
30327
- position,
30328
- onClick,
30329
- onPointerEnter: () => onHover(true),
30330
- onPointerLeave: () => onHover(false),
30331
- userData: { type: "feature", featureId: feature.id, featureType: feature.type },
30332
- children: [
30333
- isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
30334
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
30335
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
30336
- ] }),
30337
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.01, 0], rotation: [-Math.PI / 2, 0, 0], children: [
30338
- /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [0.35, 16] }),
30339
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#000000", transparent: true, opacity: 0.2 })
30340
- ] }),
30341
- model && /* @__PURE__ */ jsxRuntime.jsx("primitive", { object: model })
30342
- ]
30343
- }
30344
- );
30345
- }
30346
- function FeatureRenderer3D({
30347
- features,
30348
- cellSize = 1,
30349
- offsetX = 0,
30350
- offsetZ = 0,
30351
- onFeatureClick,
30352
- onFeatureHover,
30353
- selectedFeatureIds = []
30354
- }) {
30355
- return /* @__PURE__ */ jsxRuntime.jsx("group", { children: features.map((feature) => {
30356
- const x = (feature.x - offsetX) * cellSize;
30357
- const z = ((feature.z ?? feature.y ?? 0) - offsetZ) * cellSize;
30358
- const y = (feature.elevation ?? 0) * 0.1;
30359
- const isSelected = feature.id ? selectedFeatureIds.includes(feature.id) : false;
30360
- return /* @__PURE__ */ jsxRuntime.jsx(
30361
- FeatureModel,
30362
- {
30363
- feature,
30364
- position: [x, y, z],
30365
- isSelected,
30366
- onClick: () => onFeatureClick?.(feature),
30367
- onHover: (hovered) => onFeatureHover?.(hovered ? feature : null)
30368
- },
30369
- feature.id ?? `feature-${feature.x}-${feature.y}`
30370
- );
30371
- }) });
30372
- }
30373
- function detectAssetRoot2(modelUrl) {
30374
- const idx = modelUrl.indexOf("/3d/");
30375
- if (idx !== -1) {
30376
- return modelUrl.substring(0, idx + 4);
30377
- }
30378
- return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
30379
- }
30380
- function createGLTFLoaderForUrl(url) {
30381
- const loader = new GLTFLoader_js.GLTFLoader();
30382
- loader.setResourcePath(detectAssetRoot2(url));
30383
- return loader;
30384
- }
30385
- var AssetLoader = class {
30386
- constructor() {
30387
- __publicField(this, "objLoader");
30388
- __publicField(this, "textureLoader");
30389
- __publicField(this, "modelCache");
30390
- __publicField(this, "textureCache");
30391
- __publicField(this, "loadingPromises");
30392
- this.objLoader = new OBJLoader_js.OBJLoader();
30393
- this.textureLoader = new THREE__namespace.TextureLoader();
30394
- this.modelCache = /* @__PURE__ */ new Map();
30395
- this.textureCache = /* @__PURE__ */ new Map();
30396
- this.loadingPromises = /* @__PURE__ */ new Map();
30397
- }
30398
- /**
30399
- * Load a GLB/GLTF model
30400
- * @param url - URL to the .glb or .gltf file
30401
- * @returns Promise with loaded model scene and animations
30402
- */
30403
- async loadModel(url) {
30404
- if (this.modelCache.has(url)) {
30405
- return this.modelCache.get(url);
30406
- }
30407
- if (this.loadingPromises.has(url)) {
30408
- return this.loadingPromises.get(url);
30409
- }
30410
- const loader = createGLTFLoaderForUrl(url);
30411
- const loadPromise = loader.loadAsync(url).then((gltf) => {
30412
- const result = {
30413
- scene: gltf.scene,
30414
- animations: gltf.animations || []
30415
- };
30416
- this.modelCache.set(url, result);
30417
- this.loadingPromises.delete(url);
30418
- return result;
30419
- }).catch((error) => {
30420
- this.loadingPromises.delete(url);
30421
- throw new Error(`Failed to load model ${url}: ${error.message}`);
30422
- });
30423
- this.loadingPromises.set(url, loadPromise);
30424
- return loadPromise;
30425
- }
30426
- /**
30427
- * Load an OBJ model (fallback for non-GLB assets)
30428
- * @param url - URL to the .obj file
30429
- * @returns Promise with loaded object group
30430
- */
30431
- async loadOBJ(url) {
30432
- if (this.modelCache.has(url)) {
30433
- return this.modelCache.get(url).scene;
30434
- }
30435
- if (this.loadingPromises.has(url)) {
30436
- const result = await this.loadingPromises.get(url);
30437
- return result.scene;
30438
- }
30439
- const loadPromise = this.objLoader.loadAsync(url).then((group) => {
30440
- const result = {
30441
- scene: group,
30442
- animations: []
30443
- };
30444
- this.modelCache.set(url, result);
30445
- this.loadingPromises.delete(url);
30446
- return result;
30447
- }).catch((error) => {
30448
- this.loadingPromises.delete(url);
30449
- throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
30450
- });
30451
- this.loadingPromises.set(url, loadPromise);
30452
- return (await loadPromise).scene;
30453
- }
30454
- /**
30455
- * Load a texture
30456
- * @param url - URL to the texture image
30457
- * @returns Promise with loaded texture
30458
- */
30459
- async loadTexture(url) {
30460
- if (this.textureCache.has(url)) {
30461
- return this.textureCache.get(url);
30462
- }
30463
- if (this.loadingPromises.has(`texture:${url}`)) {
30464
- return this.loadingPromises.get(`texture:${url}`);
30465
- }
30466
- const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
30467
- texture.colorSpace = THREE__namespace.SRGBColorSpace;
30468
- this.textureCache.set(url, texture);
30469
- this.loadingPromises.delete(`texture:${url}`);
30470
- return texture;
30471
- }).catch((error) => {
30472
- this.loadingPromises.delete(`texture:${url}`);
30473
- throw new Error(`Failed to load texture ${url}: ${error.message}`);
30474
- });
30475
- this.loadingPromises.set(`texture:${url}`, loadPromise);
30476
- return loadPromise;
30477
- }
30478
- /**
30479
- * Preload multiple assets
30480
- * @param urls - Array of asset URLs to preload
30481
- * @returns Promise that resolves when all assets are loaded
30482
- */
30483
- async preload(urls) {
30484
- const promises = urls.map((url) => {
30485
- if (url.endsWith(".glb") || url.endsWith(".gltf")) {
30486
- return this.loadModel(url).catch(() => null);
30487
- } else if (url.endsWith(".obj")) {
30488
- return this.loadOBJ(url).catch(() => null);
30489
- } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
30490
- return this.loadTexture(url).catch(() => null);
30491
- }
30492
- return Promise.resolve(null);
30493
- });
30494
- await Promise.all(promises);
30495
- }
30496
- /**
30497
- * Check if a model is cached
30498
- * @param url - Model URL
30499
- */
30500
- hasModel(url) {
30501
- return this.modelCache.has(url);
30502
- }
30503
- /**
30504
- * Check if a texture is cached
30505
- * @param url - Texture URL
30506
- */
30507
- hasTexture(url) {
30508
- return this.textureCache.has(url);
30509
- }
30510
- /**
30511
- * Get cached model (throws if not cached)
30512
- * @param url - Model URL
30513
- */
30514
- getModel(url) {
30515
- const model = this.modelCache.get(url);
30516
- if (!model) {
30517
- throw new Error(`Model ${url} not in cache`);
30518
- }
30519
- return model;
30520
- }
30521
- /**
30522
- * Get cached texture (throws if not cached)
30523
- * @param url - Texture URL
30524
- */
30525
- getTexture(url) {
30526
- const texture = this.textureCache.get(url);
30527
- if (!texture) {
30528
- throw new Error(`Texture ${url} not in cache`);
30529
- }
30530
- return texture;
30531
- }
30532
- /**
30533
- * Clear all caches
30534
- */
30535
- clearCache() {
30536
- this.textureCache.forEach((texture) => {
30537
- texture.dispose();
30538
- });
30539
- this.modelCache.forEach((model) => {
30540
- model.scene.traverse((child) => {
30541
- if (child instanceof THREE__namespace.Mesh) {
30542
- child.geometry.dispose();
30543
- if (Array.isArray(child.material)) {
30544
- child.material.forEach((m) => m.dispose());
30545
- } else {
30546
- child.material.dispose();
30547
- }
30548
- }
30549
- });
30550
- });
30551
- this.modelCache.clear();
30552
- this.textureCache.clear();
30553
- this.loadingPromises.clear();
30554
- }
30555
- /**
30556
- * Get cache statistics
30557
- */
30558
- getStats() {
30559
- return {
30560
- models: this.modelCache.size,
30561
- textures: this.textureCache.size,
30562
- loading: this.loadingPromises.size
30563
- };
30564
- }
30565
- };
30566
- new AssetLoader();
30567
- function useAssetLoader(options = {}) {
30568
- const { preloadUrls = [], loader: customLoader } = options;
30569
- const loaderRef = React87.useRef(customLoader || new AssetLoader());
30570
- const [state, setState] = React87.useState({
30571
- isLoading: false,
30572
- progress: 0,
30573
- loaded: 0,
30574
- total: 0,
30575
- errors: []
30576
- });
30577
- React87.useEffect(() => {
30578
- if (preloadUrls.length > 0) {
30579
- preload(preloadUrls);
30580
- }
30581
- }, []);
30582
- const updateProgress = React87.useCallback((loaded, total) => {
30583
- setState((prev) => ({
30584
- ...prev,
30585
- loaded,
30586
- total,
30587
- progress: total > 0 ? Math.round(loaded / total * 100) : 0
30588
- }));
30589
- }, []);
30590
- const loadModel = React87.useCallback(
30591
- async (url) => {
30592
- setState((prev) => ({ ...prev, isLoading: true }));
30593
- try {
30594
- const model = await loaderRef.current.loadModel(url);
30595
- setState((prev) => ({
30596
- ...prev,
30597
- isLoading: false,
30598
- loaded: prev.loaded + 1
30599
- }));
30600
- return model;
30601
- } catch (error) {
30602
- const errorMsg = error instanceof Error ? error.message : String(error);
30603
- setState((prev) => ({
30604
- ...prev,
30605
- isLoading: false,
30606
- errors: [...prev.errors, errorMsg]
30607
- }));
30608
- throw error;
30609
- }
30610
- },
30611
- []
30612
- );
30613
- const loadOBJ = React87.useCallback(
30614
- async (url) => {
30615
- setState((prev) => ({ ...prev, isLoading: true }));
30616
- try {
30617
- const model = await loaderRef.current.loadOBJ(url);
30618
- setState((prev) => ({
30619
- ...prev,
30620
- isLoading: false,
30621
- loaded: prev.loaded + 1
30622
- }));
30623
- return model;
30624
- } catch (error) {
30625
- const errorMsg = error instanceof Error ? error.message : String(error);
30626
- setState((prev) => ({
30627
- ...prev,
30628
- isLoading: false,
30629
- errors: [...prev.errors, errorMsg]
30630
- }));
30631
- throw error;
30632
- }
30633
- },
30634
- []
30635
- );
30636
- const loadTexture = React87.useCallback(
30637
- async (url) => {
30638
- setState((prev) => ({ ...prev, isLoading: true }));
30639
- try {
30640
- const texture = await loaderRef.current.loadTexture(url);
30641
- setState((prev) => ({
30642
- ...prev,
30643
- isLoading: false,
30644
- loaded: prev.loaded + 1
30645
- }));
30646
- return texture;
30647
- } catch (error) {
30648
- const errorMsg = error instanceof Error ? error.message : String(error);
30649
- setState((prev) => ({
30650
- ...prev,
30651
- isLoading: false,
30652
- errors: [...prev.errors, errorMsg]
30653
- }));
30654
- throw error;
30655
- }
30656
- },
30657
- []
30658
- );
30659
- const preload = React87.useCallback(
30660
- async (urls) => {
30661
- setState((prev) => ({
30662
- ...prev,
30663
- isLoading: true,
30664
- total: urls.length,
30665
- loaded: 0,
30666
- errors: []
30667
- }));
30668
- let completed = 0;
30669
- const errors = [];
30670
- await Promise.all(
30671
- urls.map(async (url) => {
30672
- try {
30673
- if (url.endsWith(".glb") || url.endsWith(".gltf")) {
30674
- await loaderRef.current.loadModel(url);
30675
- } else if (url.endsWith(".obj")) {
30676
- await loaderRef.current.loadOBJ(url);
30677
- } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
30678
- await loaderRef.current.loadTexture(url);
30679
- }
30680
- completed++;
30681
- updateProgress(completed, urls.length);
30682
- } catch (error) {
30683
- const errorMsg = error instanceof Error ? error.message : String(error);
30684
- errors.push(`${url}: ${errorMsg}`);
30685
- completed++;
30686
- updateProgress(completed, urls.length);
30687
- }
30688
- })
30689
- );
30690
- setState((prev) => ({
30691
- ...prev,
30692
- isLoading: false,
30693
- errors
30694
- }));
30695
- },
30696
- [updateProgress]
30697
- );
30698
- const hasModel = React87.useCallback((url) => {
30699
- return loaderRef.current.hasModel(url);
30700
- }, []);
30701
- const hasTexture = React87.useCallback((url) => {
30702
- return loaderRef.current.hasTexture(url);
30703
- }, []);
30704
- const getModel = React87.useCallback((url) => {
30705
- try {
30706
- return loaderRef.current.getModel(url);
30707
- } catch {
30708
- return void 0;
30709
- }
30710
- }, []);
30711
- const getTexture = React87.useCallback((url) => {
30712
- try {
30713
- return loaderRef.current.getTexture(url);
30714
- } catch {
30715
- return void 0;
30716
- }
30717
- }, []);
30718
- const clearCache = React87.useCallback(() => {
30719
- loaderRef.current.clearCache();
30720
- setState({
30721
- isLoading: false,
30722
- progress: 0,
30723
- loaded: 0,
30724
- total: 0,
30725
- errors: []
30726
- });
30727
- }, []);
30728
- return {
30729
- ...state,
30730
- loadModel,
30731
- loadOBJ,
30732
- loadTexture,
30733
- preload,
30734
- hasModel,
30735
- hasTexture,
30736
- getModel,
30737
- getTexture,
30738
- clearCache
30739
- };
30740
- }
30741
- function useGameCanvas3DEvents(options) {
30742
- const {
30743
- tileClickEvent,
30744
- unitClickEvent,
30745
- featureClickEvent,
30746
- canvasClickEvent,
30747
- tileHoverEvent,
30748
- tileLeaveEvent,
30749
- unitAnimationEvent,
30750
- cameraChangeEvent,
30751
- onTileClick,
30752
- onUnitClick,
30753
- onFeatureClick,
30754
- onCanvasClick,
30755
- onTileHover,
30756
- onUnitAnimation
30757
- } = options;
30758
- const emit = useEmitEvent();
30759
- const optionsRef = React87.useRef(options);
30760
- optionsRef.current = options;
30761
- const handleTileClick = React87.useCallback(
30762
- (tile, event) => {
30763
- if (tileClickEvent) {
30764
- emit(tileClickEvent, {
30765
- tileId: tile.id,
30766
- x: tile.x,
30767
- z: tile.z ?? tile.y ?? 0,
30768
- type: tile.type,
30769
- terrain: tile.terrain,
30770
- elevation: tile.elevation
30771
- });
30772
- }
30773
- optionsRef.current.onTileClick?.(tile, event);
30774
- },
30775
- [tileClickEvent, emit]
30776
- );
30777
- const handleUnitClick = React87.useCallback(
30778
- (unit, event) => {
30779
- if (unitClickEvent) {
30780
- emit(unitClickEvent, {
30781
- unitId: unit.id,
30782
- x: unit.x,
30783
- z: unit.z ?? unit.y ?? 0,
30784
- unitType: unit.unitType,
30785
- name: unit.name,
30786
- team: unit.team,
30787
- faction: unit.faction,
30788
- health: unit.health,
30789
- maxHealth: unit.maxHealth
30790
- });
30791
- }
30792
- optionsRef.current.onUnitClick?.(unit, event);
30793
- },
30794
- [unitClickEvent, emit]
30795
- );
30796
- const handleFeatureClick = React87.useCallback(
30797
- (feature, event) => {
30798
- if (featureClickEvent) {
30799
- emit(featureClickEvent, {
30800
- featureId: feature.id,
30801
- x: feature.x,
30802
- z: feature.z ?? feature.y ?? 0,
30803
- type: feature.type,
30804
- elevation: feature.elevation
30805
- });
30806
- }
30807
- optionsRef.current.onFeatureClick?.(feature, event);
30808
- },
30809
- [featureClickEvent, emit]
30810
- );
30811
- const handleCanvasClick = React87.useCallback(
30812
- (event) => {
30813
- if (canvasClickEvent) {
30814
- emit(canvasClickEvent, {
30815
- clientX: event.clientX,
30816
- clientY: event.clientY,
30817
- button: event.button
30818
- });
30819
- }
30820
- optionsRef.current.onCanvasClick?.(event);
30821
- },
30822
- [canvasClickEvent, emit]
30823
- );
30824
- const handleTileHover = React87.useCallback(
30825
- (tile, event) => {
30826
- if (tile) {
30827
- if (tileHoverEvent) {
30828
- emit(tileHoverEvent, {
30829
- tileId: tile.id,
30830
- x: tile.x,
30831
- z: tile.z ?? tile.y ?? 0,
30832
- type: tile.type
30833
- });
30834
- }
30835
- } else {
30836
- if (tileLeaveEvent) {
30837
- emit(tileLeaveEvent, {});
30838
- }
30839
- }
30840
- optionsRef.current.onTileHover?.(tile, event);
30841
- },
30842
- [tileHoverEvent, tileLeaveEvent, emit]
30843
- );
30844
- const handleUnitAnimation = React87.useCallback(
30845
- (unitId, state) => {
30846
- if (unitAnimationEvent) {
30847
- emit(unitAnimationEvent, {
30848
- unitId,
30849
- state,
30850
- timestamp: Date.now()
30851
- });
30852
- }
30853
- optionsRef.current.onUnitAnimation?.(unitId, state);
30854
- },
30855
- [unitAnimationEvent, emit]
30856
- );
30857
- const handleCameraChange = React87.useCallback(
30858
- (position) => {
30859
- if (cameraChangeEvent) {
30860
- emit(cameraChangeEvent, {
30861
- position,
30862
- timestamp: Date.now()
30863
- });
30864
- }
30865
- },
30866
- [cameraChangeEvent, emit]
30867
- );
30868
- return {
30869
- handleTileClick,
30870
- handleUnitClick,
30871
- handleFeatureClick,
30872
- handleCanvasClick,
30873
- handleTileHover,
30874
- handleUnitAnimation,
30875
- handleCameraChange
30876
- };
30877
- }
30878
- function detectAssetRoot3(modelUrl) {
30879
- const idx = modelUrl.indexOf("/3d/");
30880
- if (idx !== -1) {
30881
- return modelUrl.substring(0, idx + 4);
30882
- }
30883
- return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
30884
- }
30885
- function useGLTFModel2(url, resourceBasePath) {
30886
- const [state, setState] = React87.useState({
30887
- model: null,
30888
- isLoading: false,
30889
- error: null
30890
- });
30891
- React87.useEffect(() => {
30892
- if (!url) {
30893
- setState({ model: null, isLoading: false, error: null });
30894
- return;
30895
- }
30896
- console.log("[ModelLoader] Loading:", url);
30897
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
30898
- const assetRoot = resourceBasePath || detectAssetRoot3(url);
30899
- const loader = new GLTFLoader.GLTFLoader();
30900
- loader.setResourcePath(assetRoot);
30901
- loader.load(
30902
- url,
30903
- (gltf) => {
30904
- console.log("[ModelLoader] Loaded:", url);
30905
- setState({
30906
- model: gltf.scene,
30907
- isLoading: false,
30908
- error: null
30909
- });
30910
- },
30911
- void 0,
30912
- (err) => {
30913
- const errorMsg = err instanceof Error ? err.message : String(err);
30914
- console.warn("[ModelLoader] Failed:", url, errorMsg);
30915
- setState({
30916
- model: null,
30917
- isLoading: false,
30918
- error: err instanceof Error ? err : new Error(String(err))
30919
- });
30920
- }
30921
- );
30922
- }, [url, resourceBasePath]);
30923
- return state;
30924
- }
30925
- function ModelLoader({
30926
- url,
30927
- position = [0, 0, 0],
30928
- scale = 1,
30929
- rotation = [0, 0, 0],
30930
- isSelected = false,
30931
- isHovered = false,
30932
- onClick,
30933
- onHover,
30934
- fallbackGeometry = "box",
30935
- castShadow = true,
30936
- receiveShadow = true,
30937
- resourceBasePath
30938
- }) {
30939
- const { model: loadedModel, isLoading, error } = useGLTFModel2(url, resourceBasePath);
30940
- const model = React87.useMemo(() => {
30941
- if (!loadedModel) return null;
30942
- const cloned = loadedModel.clone();
30943
- cloned.traverse((child) => {
30944
- if (child instanceof THREE__namespace.Mesh) {
30945
- child.castShadow = castShadow;
30946
- child.receiveShadow = receiveShadow;
30947
- }
30948
- });
30949
- return cloned;
30950
- }, [loadedModel, castShadow, receiveShadow]);
30951
- const scaleArray = React87.useMemo(() => {
30952
- if (typeof scale === "number") {
30953
- return [scale, scale, scale];
30954
- }
30955
- return scale;
30956
- }, [scale]);
30957
- const rotationRad = React87.useMemo(() => {
30958
- return [
30959
- rotation[0] * Math.PI / 180,
30960
- rotation[1] * Math.PI / 180,
30961
- rotation[2] * Math.PI / 180
30962
- ];
30963
- }, [rotation]);
30964
- if (isLoading) {
30965
- return /* @__PURE__ */ jsxRuntime.jsx("group", { position, children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
30966
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
30967
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
30968
- ] }) });
30969
- }
30970
- if (error || !model) {
30971
- if (fallbackGeometry === "none") {
30972
- return /* @__PURE__ */ jsxRuntime.jsx("group", { position });
30973
- }
30974
- const fallbackProps = {
30975
- onClick,
30976
- onPointerOver: () => onHover?.(true),
30977
- onPointerOut: () => onHover?.(false)
30978
- };
30979
- return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
30980
- (isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
30981
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
30982
- /* @__PURE__ */ jsxRuntime.jsx(
30983
- "meshBasicMaterial",
30984
- {
30985
- color: isSelected ? 16755200 : 16777215,
30986
- transparent: true,
30987
- opacity: 0.5
30988
- }
30989
- )
30990
- ] }),
30991
- fallbackGeometry === "box" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
30992
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
30993
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
30994
- ] }),
30995
- fallbackGeometry === "sphere" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
30996
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.4, 16, 16] }),
30997
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
30998
- ] }),
30999
- fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
31000
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
31001
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
31002
- ] })
31003
- ] });
31004
- }
31005
- return /* @__PURE__ */ jsxRuntime.jsxs(
31006
- "group",
31007
- {
31008
- position,
31009
- rotation: rotationRad,
31010
- onClick,
31011
- onPointerOver: () => onHover?.(true),
31012
- onPointerOut: () => onHover?.(false),
31013
- children: [
31014
- (isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
31015
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
31016
- /* @__PURE__ */ jsxRuntime.jsx(
31017
- "meshBasicMaterial",
31018
- {
31019
- color: isSelected ? 16755200 : 16777215,
31020
- transparent: true,
31021
- opacity: 0.5
31022
- }
31023
- )
31024
- ] }),
31025
- /* @__PURE__ */ jsxRuntime.jsx("primitive", { object: model, scale: scaleArray })
31026
- ]
31027
- }
31028
- );
31029
- }
31030
- var DEFAULT_GRID_CONFIG = {
31031
- cellSize: 1,
31032
- offsetX: 0,
31033
- offsetZ: 0
31034
- };
31035
- function CameraController({
31036
- onCameraChange
31037
- }) {
31038
- const { camera } = fiber.useThree();
31039
- React87.useEffect(() => {
31040
- if (onCameraChange) {
31041
- onCameraChange({
31042
- x: camera.position.x,
31043
- y: camera.position.y,
31044
- z: camera.position.z
31045
- });
31046
- }
31047
- }, [camera.position, onCameraChange]);
31048
- return null;
31049
- }
31050
- var GameCanvas3D = React87.forwardRef(
31051
- ({
31052
- tiles = [],
31053
- units = [],
31054
- features = [],
31055
- events: events2 = [],
31056
- orientation = "standard",
31057
- cameraMode = "isometric",
31058
- showGrid = true,
31059
- showCoordinates = false,
31060
- showTileInfo = false,
31061
- overlay = "default",
31062
- shadows = true,
31063
- backgroundColor = "#1a1a2e",
31064
- onTileClick,
31065
- onUnitClick,
31066
- onFeatureClick,
31067
- onCanvasClick,
31068
- onTileHover,
31069
- onUnitAnimation,
31070
- assetLoader: customAssetLoader,
31071
- tileRenderer: CustomTileRenderer,
31072
- unitRenderer: CustomUnitRenderer,
31073
- featureRenderer: CustomFeatureRenderer,
31074
- className,
31075
- isLoading: externalLoading,
31076
- error: externalError,
31077
- entity,
31078
- preloadAssets = [],
31079
- tileClickEvent,
31080
- unitClickEvent,
31081
- featureClickEvent,
31082
- canvasClickEvent,
31083
- tileHoverEvent,
31084
- tileLeaveEvent,
31085
- unitAnimationEvent,
31086
- cameraChangeEvent,
31087
- loadingMessage = "Loading 3D Scene...",
31088
- useInstancing = true,
31089
- validMoves = [],
31090
- attackTargets = [],
31091
- selectedTileIds = [],
31092
- selectedUnitId = null,
31093
- children
31094
- }, ref) => {
31095
- const containerRef = React87.useRef(null);
31096
- const controlsRef = React87.useRef(null);
31097
- const [hoveredTile, setHoveredTile] = React87.useState(null);
31098
- const [internalError, setInternalError] = React87.useState(null);
31099
- const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
31100
- preloadUrls: preloadAssets,
31101
- loader: customAssetLoader
31102
- });
31103
- const eventHandlers = useGameCanvas3DEvents({
31104
- tileClickEvent,
31105
- unitClickEvent,
31106
- featureClickEvent,
31107
- canvasClickEvent,
31108
- tileHoverEvent,
31109
- tileLeaveEvent,
31110
- unitAnimationEvent,
31111
- cameraChangeEvent,
31112
- onTileClick,
31113
- onUnitClick,
31114
- onFeatureClick,
31115
- onCanvasClick,
31116
- onTileHover,
31117
- onUnitAnimation
31118
- });
31119
- const gridBounds = React87.useMemo(() => {
31120
- if (tiles.length === 0) {
31121
- return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
31122
- }
31123
- const xs = tiles.map((t) => t.x);
31124
- const zs = tiles.map((t) => t.z || t.y || 0);
31125
- return {
31126
- minX: Math.min(...xs),
31127
- maxX: Math.max(...xs),
31128
- minZ: Math.min(...zs),
31129
- maxZ: Math.max(...zs)
31130
- };
31131
- }, [tiles]);
31132
- const cameraTarget = React87.useMemo(() => {
31133
- return [
31134
- (gridBounds.minX + gridBounds.maxX) / 2,
31135
- 0,
31136
- (gridBounds.minZ + gridBounds.maxZ) / 2
31137
- ];
31138
- }, [gridBounds]);
31139
- const gridConfig = React87.useMemo(
31140
- () => ({
31141
- ...DEFAULT_GRID_CONFIG,
31142
- offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
31143
- offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
31144
- }),
31145
- [gridBounds]
31146
- );
31147
- const gridToWorld = React87.useCallback(
31148
- (x, z, y = 0) => {
31149
- const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
31150
- const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
31151
- return [worldX, y * gridConfig.cellSize, worldZ];
31152
- },
31153
- [gridBounds, gridConfig]
31154
- );
31155
- React87.useImperativeHandle(ref, () => ({
31156
- getCameraPosition: () => {
31157
- if (controlsRef.current) {
31158
- const pos = controlsRef.current.object.position;
31159
- return new THREE__namespace.Vector3(pos.x, pos.y, pos.z);
31160
- }
31161
- return null;
31162
- },
31163
- setCameraPosition: (x, y, z) => {
31164
- if (controlsRef.current) {
31165
- controlsRef.current.object.position.set(x, y, z);
31166
- controlsRef.current.update();
31167
- }
31168
- },
31169
- lookAt: (x, y, z) => {
31170
- if (controlsRef.current) {
31171
- controlsRef.current.target.set(x, y, z);
31172
- controlsRef.current.update();
31173
- }
31174
- },
31175
- resetCamera: () => {
31176
- if (controlsRef.current) {
31177
- controlsRef.current.reset();
31178
- }
31179
- },
31180
- screenshot: () => {
31181
- const canvas = containerRef.current?.querySelector("canvas");
31182
- if (canvas) {
31183
- return canvas.toDataURL("image/png");
31184
- }
31185
- return null;
31186
- },
31187
- export: () => ({
31188
- tiles,
31189
- units,
31190
- features
31191
- })
31192
- }));
31193
- const handleTileClick = React87.useCallback(
31194
- (tile, event) => {
31195
- eventHandlers.handleTileClick(tile, event);
31196
- },
31197
- [eventHandlers]
31198
- );
31199
- const handleUnitClick = React87.useCallback(
31200
- (unit, event) => {
31201
- eventHandlers.handleUnitClick(unit, event);
31202
- },
31203
- [eventHandlers]
31204
- );
31205
- const handleFeatureClick = React87.useCallback(
31206
- (feature, event) => {
31207
- if (event) {
31208
- eventHandlers.handleFeatureClick(feature, event);
31209
- }
31210
- },
31211
- [eventHandlers]
31212
- );
31213
- const handleTileHover = React87.useCallback(
31214
- (tile, event) => {
31215
- setHoveredTile(tile);
31216
- if (event) {
31217
- eventHandlers.handleTileHover(tile, event);
31218
- }
31219
- },
31220
- [eventHandlers]
31221
- );
31222
- const cameraConfig = React87.useMemo(() => {
31223
- const size = Math.max(
31224
- gridBounds.maxX - gridBounds.minX,
31225
- gridBounds.maxZ - gridBounds.minZ
31226
- );
31227
- const distance = size * 1.5;
31228
- switch (cameraMode) {
31229
- case "isometric":
31230
- return {
31231
- position: [distance, distance * 0.8, distance],
31232
- fov: 45
31233
- };
31234
- case "top-down":
31235
- return {
31236
- position: [0, distance * 2, 0],
31237
- fov: 45
31238
- };
31239
- case "perspective":
31240
- default:
31241
- return {
31242
- position: [distance, distance, distance],
31243
- fov: 45
31244
- };
31245
- }
31246
- }, [cameraMode, gridBounds]);
31247
- const DefaultTileRenderer = React87.useCallback(
31248
- ({ tile, position }) => {
31249
- const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
31250
- const isHovered = hoveredTile?.id === tile.id;
31251
- const isValidMove = validMoves.some(
31252
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
31253
- );
31254
- const isAttackTarget = attackTargets.some(
31255
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
31256
- );
31257
- let color = 8421504;
31258
- if (tile.type === "water") color = 4491468;
31259
- else if (tile.type === "grass") color = 4500036;
31260
- else if (tile.type === "sand") color = 14535816;
31261
- else if (tile.type === "rock") color = 8947848;
31262
- else if (tile.type === "snow") color = 15658734;
31263
- let emissive = 0;
31264
- if (isSelected) emissive = 4473924;
31265
- else if (isAttackTarget) emissive = 4456448;
31266
- else if (isValidMove) emissive = 17408;
31267
- else if (isHovered) emissive = 2236962;
31268
- return /* @__PURE__ */ jsxRuntime.jsxs(
31269
- "mesh",
31270
- {
31271
- position,
31272
- onClick: (e) => handleTileClick(tile, e),
31273
- onPointerEnter: (e) => handleTileHover(tile, e),
31274
- onPointerLeave: (e) => handleTileHover(null, e),
31275
- userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
31276
- children: [
31277
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
31278
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, emissive })
31279
- ]
31280
- }
31281
- );
31282
- },
31283
- [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
31284
- );
31285
- const DefaultUnitRenderer = React87.useCallback(
31286
- ({ unit, position }) => {
31287
- const isSelected = selectedUnitId === unit.id;
31288
- const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
31289
- return /* @__PURE__ */ jsxRuntime.jsxs(
31290
- "group",
31291
- {
31292
- position,
31293
- onClick: (e) => handleUnitClick(unit, e),
31294
- userData: { type: "unit", unitId: unit.id },
31295
- children: [
31296
- isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
31297
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
31298
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
31299
- ] }),
31300
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
31301
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
31302
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
31303
- ] }),
31304
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
31305
- /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
31306
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
31307
- ] }),
31308
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
31309
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
31310
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
31311
- ] }),
31312
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
31313
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
31314
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
31315
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
31316
- ] }),
31317
- /* @__PURE__ */ jsxRuntime.jsxs(
31318
- "mesh",
31319
- {
31320
- position: [
31321
- -0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
31322
- 0,
31323
- 0.01
31324
- ],
31325
- children: [
31326
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
31327
- /* @__PURE__ */ jsxRuntime.jsx(
31328
- "meshBasicMaterial",
31329
- {
31330
- color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
31331
- }
31332
- )
31333
- ]
31334
- }
31335
- )
31336
- ] })
31337
- ]
31338
- }
31339
- );
31340
- },
31341
- [selectedUnitId, handleUnitClick]
31342
- );
31343
- const DefaultFeatureRenderer = React87.useCallback(
31344
- ({
31345
- feature,
31346
- position
31347
- }) => {
31348
- if (feature.assetUrl) {
31349
- return /* @__PURE__ */ jsxRuntime.jsx(
31350
- ModelLoader,
31351
- {
31352
- url: feature.assetUrl,
31353
- position,
31354
- scale: 0.5,
31355
- rotation: [0, feature.rotation ?? 0, 0],
31356
- onClick: () => handleFeatureClick(feature, null),
31357
- fallbackGeometry: "box"
31358
- },
31359
- feature.id
31360
- );
31361
- }
31362
- if (feature.type === "tree") {
31363
- return /* @__PURE__ */ jsxRuntime.jsxs(
31364
- "group",
31365
- {
31366
- position,
31367
- onClick: (e) => handleFeatureClick(feature, e),
31368
- userData: { type: "feature", featureId: feature.id },
31369
- children: [
31370
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.4, 0], children: [
31371
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
31372
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 9127187 })
31373
- ] }),
31374
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
31375
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
31376
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 2263842 })
31377
- ] })
31378
- ]
31379
- }
31380
- );
31381
- }
31382
- if (feature.type === "rock") {
31383
- return /* @__PURE__ */ jsxRuntime.jsxs(
31384
- "mesh",
31385
- {
31386
- position: [position[0], position[1] + 0.3, position[2]],
31387
- onClick: (e) => handleFeatureClick(feature, e),
31388
- userData: { type: "feature", featureId: feature.id },
31389
- children: [
31390
- /* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [0.3, 0] }),
31391
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 8421504 })
31392
- ]
31393
- }
31394
- );
31395
- }
31396
- return null;
31397
- },
31398
- [handleFeatureClick]
31399
- );
31400
- if (externalLoading || assetsLoading && preloadAssets.length > 0) {
31401
- return /* @__PURE__ */ jsxRuntime.jsx(
31402
- Canvas3DLoadingState,
31403
- {
31404
- progress,
31405
- loaded,
31406
- total,
31407
- message: loadingMessage,
31408
- className
31409
- }
31410
- );
31411
- }
31412
- const displayError = externalError || internalError;
31413
- if (displayError) {
31414
- return /* @__PURE__ */ jsxRuntime.jsx(Canvas3DErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "game-canvas-3d game-canvas-3d--error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__error", children: [
31415
- "Error: ",
31416
- displayError
31417
- ] }) }) });
31418
- }
31419
- return /* @__PURE__ */ jsxRuntime.jsx(
31420
- Canvas3DErrorBoundary,
31421
- {
31422
- onError: (err) => setInternalError(err.message),
31423
- onReset: () => setInternalError(null),
31424
- children: /* @__PURE__ */ jsxRuntime.jsxs(
31425
- "div",
31426
- {
31427
- ref: containerRef,
31428
- className: `game-canvas-3d ${className || ""}`,
31429
- "data-orientation": orientation,
31430
- "data-camera-mode": cameraMode,
31431
- "data-overlay": overlay,
31432
- children: [
31433
- /* @__PURE__ */ jsxRuntime.jsxs(
31434
- fiber.Canvas,
31435
- {
31436
- shadows,
31437
- camera: {
31438
- position: cameraConfig.position,
31439
- fov: cameraConfig.fov,
31440
- near: 0.1,
31441
- far: 1e3
31442
- },
31443
- style: { background: backgroundColor },
31444
- onClick: (e) => {
31445
- if (e.target === e.currentTarget) {
31446
- eventHandlers.handleCanvasClick(e);
31447
- }
31448
- },
31449
- children: [
31450
- /* @__PURE__ */ jsxRuntime.jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
31451
- /* @__PURE__ */ jsxRuntime.jsx("ambientLight", { intensity: 0.6 }),
31452
- /* @__PURE__ */ jsxRuntime.jsx(
31453
- "directionalLight",
31454
- {
31455
- position: [10, 20, 10],
31456
- intensity: 0.8,
31457
- castShadow: shadows,
31458
- "shadow-mapSize": [2048, 2048]
31459
- }
31460
- ),
31461
- /* @__PURE__ */ jsxRuntime.jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
31462
- showGrid && /* @__PURE__ */ jsxRuntime.jsx(
31463
- drei.Grid,
31464
- {
31465
- args: [
31466
- Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
31467
- Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
31468
- ],
31469
- position: [
31470
- (gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
31471
- 0,
31472
- (gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
31473
- ],
31474
- cellSize: 1,
31475
- cellThickness: 1,
31476
- cellColor: "#444444",
31477
- sectionSize: 5,
31478
- sectionThickness: 1.5,
31479
- sectionColor: "#666666",
31480
- fadeDistance: 50,
31481
- fadeStrength: 1
31482
- }
31483
- ),
31484
- tiles.map((tile, index) => {
31485
- const position = gridToWorld(
31486
- tile.x,
31487
- tile.z ?? tile.y ?? 0,
31488
- tile.elevation ?? 0
31489
- );
31490
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
31491
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
31492
- }),
31493
- features.map((feature, index) => {
31494
- const position = gridToWorld(
31495
- feature.x,
31496
- feature.z ?? feature.y ?? 0,
31497
- (feature.elevation ?? 0) + 0.5
31498
- );
31499
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
31500
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
31501
- }),
31502
- units.map((unit) => {
31503
- const position = gridToWorld(
31504
- unit.x ?? 0,
31505
- unit.z ?? unit.y ?? 0,
31506
- (unit.elevation ?? 0) + 0.5
31507
- );
31508
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
31509
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
31510
- }),
31511
- children,
31512
- /* @__PURE__ */ jsxRuntime.jsx(
31513
- drei.OrbitControls,
31514
- {
31515
- ref: controlsRef,
31516
- target: cameraTarget,
31517
- enableDamping: true,
31518
- dampingFactor: 0.05,
31519
- minDistance: 2,
31520
- maxDistance: 100,
31521
- maxPolarAngle: Math.PI / 2 - 0.1
31522
- }
31523
- )
31524
- ]
31525
- }
31526
- ),
31527
- showCoordinates && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__coordinates", children: [
31528
- "X: ",
31529
- hoveredTile.x,
31530
- ", Z: ",
31531
- hoveredTile.z ?? hoveredTile.y ?? 0
31532
- ] }),
31533
- showTileInfo && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__tile-info", children: [
31534
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
31535
- hoveredTile.terrain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
31536
- ] })
31537
- ]
31538
- }
31539
- )
29725
+ Box,
29726
+ {
29727
+ className: "w-full overflow-auto p-4 font-mono text-sm",
29728
+ style: { height, fontSize: `${zoom}%` },
29729
+ children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: activeContent })
31540
29730
  }
31541
29731
  );
31542
- }
31543
- );
31544
- GameCanvas3D.displayName = "GameCanvas3D";
31545
- function GameCanvas3DBattleTemplate({
31546
- entity,
31547
- cameraMode = "perspective",
31548
- showGrid = true,
31549
- shadows = true,
31550
- backgroundColor = "#2a1a1a",
31551
- tileClickEvent,
31552
- unitClickEvent,
31553
- unitAttackEvent,
31554
- unitMoveEvent,
31555
- endTurnEvent,
31556
- exitEvent,
31557
- selectedUnitId,
31558
- validMoves,
31559
- attackTargets,
31560
- className
31561
- }) {
31562
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
31563
- if (!resolved) return null;
31564
- return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("game-canvas-3d-battle-template", className), children: [
31565
- /* @__PURE__ */ jsxRuntime.jsx(
31566
- GameCanvas3D,
29732
+ };
29733
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
29734
+ tabItems && tabItems.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsxRuntime.jsx(
29735
+ Tabs,
31567
29736
  {
31568
- tiles: resolved.tiles,
31569
- units: resolved.units,
31570
- features: resolved.features,
31571
- cameraMode,
31572
- showGrid,
31573
- showCoordinates: false,
31574
- showTileInfo: false,
31575
- shadows,
31576
- backgroundColor,
31577
- tileClickEvent,
31578
- unitClickEvent,
31579
- selectedUnitId,
31580
- validMoves,
31581
- attackTargets,
31582
- className: "game-canvas-3d-battle-template__canvas"
29737
+ tabs: tabItems,
29738
+ activeTab: `doc-${activeDocIndex}`,
29739
+ onTabChange: (id) => {
29740
+ const idx = parseInt(id.replace("doc-", ""), 10);
29741
+ setActiveDocIndex(idx);
29742
+ }
31583
29743
  }
31584
- ),
31585
- resolved.currentTurn && /* @__PURE__ */ jsxRuntime.jsxs(
29744
+ ) }),
29745
+ showToolbar && /* @__PURE__ */ jsxRuntime.jsxs(
31586
29746
  HStack,
31587
29747
  {
31588
29748
  gap: "sm",
31589
29749
  align: "center",
31590
- className: cn("battle-template__turn-indicator", `battle-template__turn-indicator--${resolved.currentTurn}`),
29750
+ justify: "between",
29751
+ className: "px-4 py-2 border-b border-[var(--color-border)] bg-[var(--color-muted)]/30",
31591
29752
  children: [
31592
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "turn-indicator__label", children: resolved.currentTurn === "player" ? "Your Turn" : "Enemy's Turn" }),
31593
- resolved.round && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "turn-indicator__round", children: [
31594
- "Round ",
31595
- resolved.round
29753
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", children: [
29754
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons.FileText, size: "sm", className: "text-[var(--color-muted-foreground)]" }),
29755
+ title && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "truncate max-w-[200px]", children: title })
29756
+ ] }),
29757
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
29758
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ZoomOut, onClick: handleZoomOut }),
29759
+ /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", color: "secondary", className: "tabular-nums w-10 text-center", children: [
29760
+ zoom,
29761
+ "%"
29762
+ ] }),
29763
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ZoomIn, onClick: handleZoomIn }),
29764
+ totalPages && totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29765
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-px h-4 bg-[var(--color-border)] mx-1" }),
29766
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ChevronLeft, onClick: handlePagePrev, disabled: currentPage <= 1 }),
29767
+ /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: [
29768
+ currentPage,
29769
+ " / ",
29770
+ totalPages
29771
+ ] }),
29772
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.ChevronRight, onClick: handlePageNext, disabled: currentPage >= totalPages })
29773
+ ] }),
29774
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-px h-4 bg-[var(--color-border)] mx-1" }),
29775
+ showDownload && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.Download, onClick: handleDownload }),
29776
+ showPrint && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", icon: LucideIcons.Printer, onClick: handlePrint }),
29777
+ actions?.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
29778
+ Badge,
29779
+ {
29780
+ variant: "default",
29781
+ className: "cursor-pointer hover:opacity-80 transition-opacity",
29782
+ onClick: () => handleAction(action),
29783
+ children: action.label
29784
+ },
29785
+ idx
29786
+ ))
31596
29787
  ] })
31597
29788
  ]
31598
29789
  }
31599
- )
31600
- ] });
31601
- }
31602
- GameCanvas3DBattleTemplate.displayName = "GameCanvas3DBattleTemplate";
31603
- function GameCanvas3DCastleTemplate({
31604
- entity,
31605
- cameraMode = "isometric",
31606
- showGrid = true,
31607
- shadows = true,
31608
- backgroundColor = "#1e1e2e",
31609
- buildingClickEvent,
31610
- unitClickEvent,
31611
- buildEvent,
31612
- recruitEvent,
31613
- exitEvent,
31614
- selectedBuildingId,
31615
- selectedTileIds = [],
31616
- availableBuildSites,
31617
- showHeader = true,
31618
- className
31619
- }) {
31620
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
31621
- if (!resolved) return null;
31622
- return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("game-canvas-3d-castle-template", className), children: [
31623
- showHeader && resolved.name && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "center", className: "castle-template__header", children: [
31624
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", className: "header__name", children: resolved.name }),
31625
- resolved.level && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "header__level", children: [
31626
- "Level ",
31627
- resolved.level
31628
- ] }),
31629
- resolved.owner && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", className: "header__owner", children: resolved.owner })
31630
- ] }),
31631
- /* @__PURE__ */ jsxRuntime.jsx(
31632
- GameCanvas3D,
31633
- {
31634
- tiles: resolved.tiles,
31635
- units: resolved.units,
31636
- features: resolved.features,
31637
- cameraMode,
31638
- showGrid,
31639
- showCoordinates: false,
31640
- showTileInfo: false,
31641
- shadows,
31642
- backgroundColor,
31643
- featureClickEvent: buildingClickEvent,
31644
- unitClickEvent,
31645
- selectedTileIds,
31646
- validMoves: availableBuildSites,
31647
- className: "game-canvas-3d-castle-template__canvas"
31648
- }
31649
29790
  ),
31650
- resolved.units.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", className: "castle-template__garrison-info", children: [
31651
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "garrison-info__label", children: "Garrison:" }),
31652
- /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", weight: "bold", className: "garrison-info__count", children: [
31653
- resolved.units.length,
31654
- " units"
31655
- ] })
31656
- ] })
31657
- ] });
29791
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full overflow-hidden bg-[var(--color-muted)]/20", children: renderContent() })
29792
+ ] }) });
29793
+ };
29794
+ DocumentViewer.displayName = "DocumentViewer";
29795
+ function extractTitle(children) {
29796
+ if (!React87__namespace.default.isValidElement(children)) return void 0;
29797
+ const props = children.props;
29798
+ if (typeof props.title === "string") {
29799
+ return props.title;
29800
+ }
29801
+ return void 0;
31658
29802
  }
31659
- GameCanvas3DCastleTemplate.displayName = "GameCanvas3DCastleTemplate";
31660
- function GameCanvas3DWorldMapTemplate({
31661
- entity,
31662
- cameraMode = "isometric",
31663
- showGrid = true,
31664
- showCoordinates = true,
31665
- showTileInfo = true,
31666
- shadows = true,
31667
- backgroundColor = "#1a1a2e",
31668
- tileClickEvent,
31669
- unitClickEvent,
31670
- featureClickEvent,
31671
- tileHoverEvent,
31672
- tileLeaveEvent,
31673
- cameraChangeEvent,
31674
- selectedUnitId,
31675
- validMoves,
31676
- attackTargets,
29803
+ var DrawerSlot = ({
29804
+ children,
29805
+ title: overrideTitle,
29806
+ position = "right",
29807
+ size = "md",
31677
29808
  className
31678
- }) {
31679
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
31680
- if (!resolved) return null;
29809
+ }) => {
29810
+ const eventBus = useEventBus();
29811
+ const isOpen = Boolean(children);
29812
+ const title = overrideTitle || extractTitle(children);
29813
+ const handleClose = () => {
29814
+ eventBus.emit("UI:CLOSE");
29815
+ eventBus.emit("UI:CANCEL");
29816
+ };
29817
+ if (!isOpen) return null;
31681
29818
  return /* @__PURE__ */ jsxRuntime.jsx(
31682
- GameCanvas3D,
29819
+ Drawer,
31683
29820
  {
31684
- tiles: resolved.tiles,
31685
- units: resolved.units,
31686
- features: resolved.features,
31687
- cameraMode,
31688
- showGrid,
31689
- showCoordinates,
31690
- showTileInfo,
31691
- shadows,
31692
- backgroundColor,
31693
- tileClickEvent,
31694
- unitClickEvent,
31695
- featureClickEvent,
31696
- tileHoverEvent,
31697
- tileLeaveEvent,
31698
- cameraChangeEvent,
31699
- selectedUnitId,
31700
- validMoves,
31701
- attackTargets,
31702
- className
29821
+ isOpen,
29822
+ onClose: handleClose,
29823
+ title,
29824
+ position,
29825
+ width: size,
29826
+ className,
29827
+ children
31703
29828
  }
31704
29829
  );
31705
- }
31706
- GameCanvas3DWorldMapTemplate.displayName = "GameCanvas3DWorldMapTemplate";
29830
+ };
29831
+ DrawerSlot.displayName = "DrawerSlot";
31707
29832
  var GameShell = ({
31708
29833
  appName = "Game",
31709
29834
  hud,
@@ -32220,55 +30345,6 @@ var GraphCanvas = ({
32220
30345
  ] }) });
32221
30346
  };
32222
30347
  GraphCanvas.displayName = "GraphCanvas";
32223
- function Lighting3D({
32224
- ambientIntensity = 0.6,
32225
- ambientColor = "#ffffff",
32226
- directionalIntensity = 0.8,
32227
- directionalColor = "#ffffff",
32228
- directionalPosition = [10, 20, 10],
32229
- shadows = true,
32230
- shadowMapSize = 2048,
32231
- shadowCameraSize = 20,
32232
- showHelpers = false
32233
- }) {
32234
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
32235
- /* @__PURE__ */ jsxRuntime.jsx("ambientLight", { intensity: ambientIntensity, color: ambientColor }),
32236
- /* @__PURE__ */ jsxRuntime.jsx(
32237
- "directionalLight",
32238
- {
32239
- position: directionalPosition,
32240
- intensity: directionalIntensity,
32241
- color: directionalColor,
32242
- castShadow: shadows,
32243
- "shadow-mapSize": [shadowMapSize, shadowMapSize],
32244
- "shadow-camera-left": -shadowCameraSize,
32245
- "shadow-camera-right": shadowCameraSize,
32246
- "shadow-camera-top": shadowCameraSize,
32247
- "shadow-camera-bottom": -shadowCameraSize,
32248
- "shadow-camera-near": 0.1,
32249
- "shadow-camera-far": 100,
32250
- "shadow-bias": -1e-3
32251
- }
32252
- ),
32253
- /* @__PURE__ */ jsxRuntime.jsx(
32254
- "hemisphereLight",
32255
- {
32256
- intensity: 0.3,
32257
- color: "#87ceeb",
32258
- groundColor: "#362d1d"
32259
- }
32260
- ),
32261
- showHelpers && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
32262
- "directionalLightHelper",
32263
- {
32264
- args: [
32265
- new THREE__namespace.DirectionalLight(directionalColor, directionalIntensity),
32266
- 5
32267
- ]
32268
- }
32269
- ) })
32270
- ] });
32271
- }
32272
30348
  var COLUMN_CLASSES = {
32273
30349
  2: "grid-cols-2",
32274
30350
  3: "grid-cols-2 sm:grid-cols-3",
@@ -32511,92 +30587,6 @@ var ModalSlot = ({
32511
30587
  );
32512
30588
  };
32513
30589
  ModalSlot.displayName = "ModalSlot";
32514
- function PhysicsObject3D({
32515
- entityId,
32516
- modelUrl,
32517
- initialPosition = [0, 0, 0],
32518
- initialVelocity = [0, 0, 0],
32519
- mass = 1,
32520
- gravity = 9.8,
32521
- groundY = 0,
32522
- scale = 1,
32523
- onPhysicsUpdate,
32524
- onGroundHit,
32525
- onCollision
32526
- }) {
32527
- const groupRef = React87.useRef(null);
32528
- const physicsStateRef = React87.useRef({
32529
- id: entityId,
32530
- x: initialPosition[0],
32531
- y: initialPosition[1],
32532
- z: initialPosition[2],
32533
- vx: initialVelocity[0],
32534
- vy: initialVelocity[1],
32535
- vz: initialVelocity[2],
32536
- rx: 0,
32537
- ry: 0,
32538
- rz: 0,
32539
- isGrounded: false,
32540
- gravity,
32541
- friction: 0.8,
32542
- mass,
32543
- state: "Active"
32544
- });
32545
- const groundHitRef = React87.useRef(false);
32546
- React87.useEffect(() => {
32547
- if (groupRef.current) {
32548
- groupRef.current.position.set(
32549
- initialPosition[0],
32550
- initialPosition[1],
32551
- initialPosition[2]
32552
- );
32553
- }
32554
- }, []);
32555
- fiber.useFrame((state, delta) => {
32556
- const physics = physicsStateRef.current;
32557
- if (physics.state !== "Active") return;
32558
- const dt = Math.min(delta, 0.1);
32559
- if (!physics.isGrounded) {
32560
- physics.vy -= physics.gravity * dt;
32561
- }
32562
- physics.x += physics.vx * dt;
32563
- physics.y += physics.vy * dt;
32564
- physics.z += physics.vz * dt;
32565
- const airResistance = Math.pow(0.99, dt * 60);
32566
- physics.vx *= airResistance;
32567
- physics.vz *= airResistance;
32568
- if (physics.y <= groundY) {
32569
- physics.y = groundY;
32570
- if (!physics.isGrounded) {
32571
- physics.isGrounded = true;
32572
- groundHitRef.current = true;
32573
- physics.vx *= physics.friction;
32574
- physics.vz *= physics.friction;
32575
- onGroundHit?.();
32576
- }
32577
- physics.vy = 0;
32578
- } else {
32579
- physics.isGrounded = false;
32580
- }
32581
- if (groupRef.current) {
32582
- groupRef.current.position.set(physics.x, physics.y, physics.z);
32583
- if (!physics.isGrounded) {
32584
- physics.rx += physics.vz * dt * 0.5;
32585
- physics.rz -= physics.vx * dt * 0.5;
32586
- groupRef.current.rotation.set(physics.rx, physics.ry, physics.rz);
32587
- }
32588
- }
32589
- onPhysicsUpdate?.({ ...physics });
32590
- });
32591
- const scaleArray = typeof scale === "number" ? [scale, scale, scale] : scale;
32592
- return /* @__PURE__ */ jsxRuntime.jsx("group", { ref: groupRef, scale: scaleArray, children: /* @__PURE__ */ jsxRuntime.jsx(
32593
- ModelLoader,
32594
- {
32595
- url: modelUrl,
32596
- fallbackGeometry: "box"
32597
- }
32598
- ) });
32599
- }
32600
30590
 
32601
30591
  // lib/traitRegistry.ts
32602
30592
  var traits = /* @__PURE__ */ new Map();
@@ -33744,30 +31734,6 @@ function RuntimeDebugger({
33744
31734
  );
33745
31735
  }
33746
31736
  RuntimeDebugger.displayName = "RuntimeDebugger";
33747
- function Scene3D({ background = "#1a1a2e", fog, children }) {
33748
- const { scene } = fiber.useThree();
33749
- const initializedRef = React87.useRef(false);
33750
- React87.useEffect(() => {
33751
- if (initializedRef.current) return;
33752
- initializedRef.current = true;
33753
- if (background.startsWith("#") || background.startsWith("rgb")) {
33754
- scene.background = new THREE__namespace.Color(background);
33755
- } else {
33756
- const loader = new THREE__namespace.TextureLoader();
33757
- loader.load(background, (texture) => {
33758
- scene.background = texture;
33759
- });
33760
- }
33761
- if (fog) {
33762
- scene.fog = new THREE__namespace.Fog(fog.color, fog.near, fog.far);
33763
- }
33764
- return () => {
33765
- scene.background = null;
33766
- scene.fog = null;
33767
- };
33768
- }, [scene, background, fog]);
33769
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
33770
- }
33771
31737
  var SignaturePad = ({
33772
31738
  label = "Signature",
33773
31739
  helperText = "Draw your signature above",
@@ -33944,174 +31910,6 @@ var SignaturePad = ({
33944
31910
  ] }) });
33945
31911
  };
33946
31912
  SignaturePad.displayName = "SignaturePad";
33947
- var DEFAULT_TERRAIN_COLORS = {
33948
- grass: "#44aa44",
33949
- dirt: "#8b7355",
33950
- sand: "#ddcc88",
33951
- water: "#4488cc",
33952
- rock: "#888888",
33953
- snow: "#eeeeee",
33954
- forest: "#228b22",
33955
- desert: "#d4a574",
33956
- mountain: "#696969",
33957
- swamp: "#556b2f"
33958
- };
33959
- function TileRenderer({
33960
- tiles,
33961
- cellSize = 1,
33962
- offsetX = 0,
33963
- offsetZ = 0,
33964
- useInstancing = true,
33965
- terrainColors = DEFAULT_TERRAIN_COLORS,
33966
- onTileClick,
33967
- onTileHover,
33968
- selectedTileIds = [],
33969
- validMoves = [],
33970
- attackTargets = []
33971
- }) {
33972
- const meshRef = React87.useRef(null);
33973
- const geometry = React87.useMemo(() => {
33974
- return new THREE__namespace.BoxGeometry(cellSize * 0.95, 0.2, cellSize * 0.95);
33975
- }, [cellSize]);
33976
- const material = React87.useMemo(() => {
33977
- return new THREE__namespace.MeshStandardMaterial({
33978
- roughness: 0.8,
33979
- metalness: 0.1
33980
- });
33981
- }, []);
33982
- const { positions, colors, tileMap } = React87.useMemo(() => {
33983
- const pos = [];
33984
- const cols = [];
33985
- const map = /* @__PURE__ */ new Map();
33986
- tiles.forEach((tile) => {
33987
- const x = (tile.x - offsetX) * cellSize;
33988
- const z = ((tile.z ?? tile.y ?? 0) - offsetZ) * cellSize;
33989
- const y = (tile.elevation ?? 0) * 0.1;
33990
- pos.push(new THREE__namespace.Vector3(x, y, z));
33991
- const colorHex = terrainColors[tile.type || ""] || terrainColors[tile.terrain || ""] || "#808080";
33992
- const color = new THREE__namespace.Color(colorHex);
33993
- const isValidMove = validMoves.some(
33994
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
33995
- );
33996
- const isAttackTarget = attackTargets.some(
33997
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
33998
- );
33999
- const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
34000
- if (isSelected) {
34001
- color.addScalar(0.3);
34002
- } else if (isAttackTarget) {
34003
- color.setHex(16729156);
34004
- } else if (isValidMove) {
34005
- color.setHex(4521796);
34006
- }
34007
- cols.push(color);
34008
- map.set(`${tile.x},${tile.z ?? tile.y ?? 0}`, tile);
34009
- });
34010
- return { positions: pos, colors: cols, tileMap: map };
34011
- }, [tiles, cellSize, offsetX, offsetZ, terrainColors, selectedTileIds, validMoves, attackTargets]);
34012
- React87.useEffect(() => {
34013
- if (!meshRef.current || !useInstancing) return;
34014
- const mesh = meshRef.current;
34015
- mesh.count = positions.length;
34016
- const dummy = new THREE__namespace.Object3D();
34017
- positions.forEach((pos, i) => {
34018
- dummy.position.copy(pos);
34019
- dummy.updateMatrix();
34020
- mesh.setMatrixAt(i, dummy.matrix);
34021
- if (mesh.setColorAt) {
34022
- mesh.setColorAt(i, colors[i]);
34023
- }
34024
- });
34025
- mesh.instanceMatrix.needsUpdate = true;
34026
- if (mesh.instanceColor) {
34027
- mesh.instanceColor.needsUpdate = true;
34028
- }
34029
- }, [positions, colors, useInstancing]);
34030
- const handlePointerMove = (e) => {
34031
- if (!onTileHover) return;
34032
- const instanceId = e.instanceId;
34033
- if (instanceId !== void 0) {
34034
- const pos = positions[instanceId];
34035
- if (pos) {
34036
- const gridX = Math.round(pos.x / cellSize + offsetX);
34037
- const gridZ = Math.round(pos.z / cellSize + offsetZ);
34038
- const tile = tileMap.get(`${gridX},${gridZ}`);
34039
- if (tile) {
34040
- onTileHover(tile);
34041
- }
34042
- }
34043
- }
34044
- };
34045
- const handleClick = (e) => {
34046
- if (!onTileClick) return;
34047
- const instanceId = e.instanceId;
34048
- if (instanceId !== void 0) {
34049
- const pos = positions[instanceId];
34050
- if (pos) {
34051
- const gridX = Math.round(pos.x / cellSize + offsetX);
34052
- const gridZ = Math.round(pos.z / cellSize + offsetZ);
34053
- const tile = tileMap.get(`${gridX},${gridZ}`);
34054
- if (tile) {
34055
- onTileClick(tile);
34056
- }
34057
- }
34058
- }
34059
- };
34060
- const renderIndividualTiles = () => {
34061
- return tiles.map((tile) => {
34062
- const x = (tile.x - offsetX) * cellSize;
34063
- const z = ((tile.z ?? tile.y ?? 0) - offsetZ) * cellSize;
34064
- const y = (tile.elevation ?? 0) * 0.1;
34065
- const colorHex = terrainColors[tile.type || ""] || terrainColors[tile.terrain || ""] || "#808080";
34066
- const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
34067
- const isValidMove = validMoves.some(
34068
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
34069
- );
34070
- const isAttackTarget = attackTargets.some(
34071
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
34072
- );
34073
- let emissive = "#000000";
34074
- if (isSelected) emissive = "#444444";
34075
- else if (isAttackTarget) emissive = "#440000";
34076
- else if (isValidMove) emissive = "#004400";
34077
- return /* @__PURE__ */ jsxRuntime.jsxs(
34078
- "mesh",
34079
- {
34080
- position: [x, y, z],
34081
- userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
34082
- onClick: () => onTileClick?.(tile),
34083
- onPointerEnter: () => onTileHover?.(tile),
34084
- onPointerLeave: () => onTileHover?.(null),
34085
- children: [
34086
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [cellSize * 0.95, 0.2, cellSize * 0.95] }),
34087
- /* @__PURE__ */ jsxRuntime.jsx(
34088
- "meshStandardMaterial",
34089
- {
34090
- color: colorHex,
34091
- emissive,
34092
- roughness: 0.8,
34093
- metalness: 0.1
34094
- }
34095
- )
34096
- ]
34097
- },
34098
- tile.id ?? `tile-${tile.x}-${tile.y}`
34099
- );
34100
- });
34101
- };
34102
- if (useInstancing && tiles.length > 0) {
34103
- return /* @__PURE__ */ jsxRuntime.jsx(
34104
- "instancedMesh",
34105
- {
34106
- ref: meshRef,
34107
- args: [geometry, material, tiles.length],
34108
- onPointerMove: handlePointerMove,
34109
- onClick: handleClick
34110
- }
34111
- );
34112
- }
34113
- return /* @__PURE__ */ jsxRuntime.jsx("group", { children: renderIndividualTiles() });
34114
- }
34115
31913
  var STATUS_STYLES3 = {
34116
31914
  complete: {
34117
31915
  dotColor: "text-[var(--color-success)]",
@@ -34293,111 +32091,6 @@ var ToastSlot = ({
34293
32091
  ) });
34294
32092
  };
34295
32093
  ToastSlot.displayName = "ToastSlot";
34296
- function UnitVisual({ unit, position, isSelected, onClick }) {
34297
- const groupRef = React87.useRef(null);
34298
- const [animationState, setAnimationState] = React87.useState("idle");
34299
- const [isHovered, setIsHovered] = React87.useState(false);
34300
- const teamColor = React87.useMemo(() => {
34301
- if (unit.faction === "player" || unit.team === "player") return 4491519;
34302
- if (unit.faction === "enemy" || unit.team === "enemy") return 16729156;
34303
- if (unit.faction === "neutral" || unit.team === "neutral") return 16777028;
34304
- return 8947848;
34305
- }, [unit.faction, unit.team]);
34306
- fiber.useFrame((state) => {
34307
- if (groupRef.current && animationState === "idle") {
34308
- const y = position[1] + Math.sin(state.clock.elapsedTime * 2 + position[0]) * 0.05;
34309
- groupRef.current.position.y = y;
34310
- }
34311
- });
34312
- const healthPercent = React87.useMemo(() => {
34313
- if (unit.health === void 0 || unit.maxHealth === void 0) return 1;
34314
- return Math.max(0, Math.min(1, unit.health / unit.maxHealth));
34315
- }, [unit.health, unit.maxHealth]);
34316
- const healthColor = React87.useMemo(() => {
34317
- if (healthPercent > 0.5) return "#44aa44";
34318
- if (healthPercent > 0.25) return "#aaaa44";
34319
- return "#ff4444";
34320
- }, [healthPercent]);
34321
- return /* @__PURE__ */ jsxRuntime.jsxs(
34322
- "group",
34323
- {
34324
- ref: groupRef,
34325
- position,
34326
- onClick,
34327
- onPointerEnter: () => setIsHovered(true),
34328
- onPointerLeave: () => setIsHovered(false),
34329
- userData: { type: "unit", unitId: unit.id },
34330
- children: [
34331
- isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
34332
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
34333
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
34334
- ] }),
34335
- isHovered && !isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
34336
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
34337
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffffff", transparent: true, opacity: 0.5 })
34338
- ] }),
34339
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.1, 0], children: [
34340
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.25, 0.25, 0.1, 8] }),
34341
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: teamColor })
34342
- ] }),
34343
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.5, 0], children: [
34344
- /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.15, 0.5, 4, 8] }),
34345
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: teamColor })
34346
- ] }),
34347
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
34348
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
34349
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: teamColor })
34350
- ] }),
34351
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 1.3, 0], children: [
34352
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.06] }),
34353
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#333333" })
34354
- ] }),
34355
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25 + 0.25 * healthPercent, 1.3, 0.01], children: [
34356
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5 * healthPercent, 0.04] }),
34357
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: healthColor })
34358
- ] }),
34359
- unit.name && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 1.5, 0], children: [
34360
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.4, 0.1] }),
34361
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#000000", transparent: true, opacity: 0.5 })
34362
- ] })
34363
- ]
34364
- }
34365
- );
34366
- }
34367
- function UnitRenderer({
34368
- units,
34369
- cellSize = 1,
34370
- offsetX = 0,
34371
- offsetZ = 0,
34372
- selectedUnitId,
34373
- onUnitClick,
34374
- onAnimationStateChange,
34375
- animationSpeed = 1
34376
- }) {
34377
- const handleUnitClick = React87__namespace.default.useCallback(
34378
- (unit) => {
34379
- onUnitClick?.(unit);
34380
- },
34381
- [onUnitClick]
34382
- );
34383
- return /* @__PURE__ */ jsxRuntime.jsx("group", { children: units.map((unit) => {
34384
- const unitX = unit.x ?? unit.position?.x ?? 0;
34385
- const unitY = unit.z ?? unit.y ?? unit.position?.y ?? 0;
34386
- const x = (unitX - offsetX) * cellSize;
34387
- const z = (unitY - offsetZ) * cellSize;
34388
- const y = (unit.elevation ?? 0) * 0.1 + 0.5;
34389
- return /* @__PURE__ */ jsxRuntime.jsx(
34390
- UnitVisual,
34391
- {
34392
- unit,
34393
- position: [x, y, z],
34394
- isSelected: selectedUnitId === unit.id,
34395
- onClick: () => handleUnitClick(unit)
34396
- },
34397
- unit.id
34398
- );
34399
- }) });
34400
- }
34401
32094
  function WorldMapTemplate({
34402
32095
  entity,
34403
32096
  scale = 0.4,
@@ -34425,6 +32118,33 @@ function WorldMapTemplate({
34425
32118
  WorldMapTemplate.displayName = "WorldMapTemplate";
34426
32119
 
34427
32120
  // components/organisms/component-registry.generated.ts
32121
+ function lazyThree(name, loader) {
32122
+ const Lazy = React87__namespace.default.lazy(() => loader().then((m) => ({ default: m[name] })));
32123
+ function ThreeWrapper(props) {
32124
+ return React87__namespace.default.createElement(
32125
+ React87__namespace.default.Suspense,
32126
+ { fallback: null },
32127
+ React87__namespace.default.createElement(Lazy, props)
32128
+ );
32129
+ }
32130
+ ThreeWrapper.displayName = `Lazy(${name})`;
32131
+ return ThreeWrapper;
32132
+ }
32133
+ var Camera3D = lazyThree("Camera3D", () => import('@almadar/ui/components/organisms/game/three'));
32134
+ var Canvas3DErrorBoundary = lazyThree("Canvas3DErrorBoundary", () => import('@almadar/ui/components/organisms/game/three'));
32135
+ var Canvas3DLoadingState = lazyThree("Canvas3DLoadingState", () => import('@almadar/ui/components/organisms/game/three'));
32136
+ var FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/organisms/game/three'));
32137
+ var FeatureRenderer3D = lazyThree("FeatureRenderer3D", () => import('@almadar/ui/components/organisms/game/three'));
32138
+ var GameCanvas3D = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/organisms/game/three'));
32139
+ var GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/organisms/game/three'));
32140
+ var GameCanvas3DCastleTemplate = lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/organisms/game/three'));
32141
+ var GameCanvas3DWorldMapTemplate = lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/organisms/game/three'));
32142
+ var Lighting3D = lazyThree("Lighting3D", () => import('@almadar/ui/components/organisms/game/three'));
32143
+ var ModelLoader = lazyThree("ModelLoader", () => import('@almadar/ui/components/organisms/game/three'));
32144
+ var PhysicsObject3D = lazyThree("PhysicsObject3D", () => import('@almadar/ui/components/organisms/game/three'));
32145
+ var Scene3D = lazyThree("Scene3D", () => import('@almadar/ui/components/organisms/game/three'));
32146
+ var TileRenderer = lazyThree("TileRenderer", () => import('@almadar/ui/components/organisms/game/three'));
32147
+ var UnitRenderer = lazyThree("UnitRenderer", () => import('@almadar/ui/components/organisms/game/three'));
34428
32148
  var COMPONENT_REGISTRY = {
34429
32149
  "Accordion": AccordionPattern,
34430
32150
  "AccordionPattern": AccordionPattern,