@almadar/ui 2.16.0 → 2.16.1

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React113 = require('react');
3
+ var React110 = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  require('@tanstack/react-query');
6
6
  require('react-dom');
@@ -20,12 +20,6 @@ var remarkMath = require('remark-math');
20
20
  var rehypeKatex = require('rehype-katex');
21
21
  var SyntaxHighlighter = require('react-syntax-highlighter/dist/esm/prism');
22
22
  var dark = require('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus');
23
- var fiber = require('@react-three/fiber');
24
- var drei = require('@react-three/drei');
25
- var THREE = require('three');
26
- var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
27
- var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
28
- var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
29
23
  var core = require('@almadar/core');
30
24
  var runtime = require('@almadar/runtime');
31
25
 
@@ -49,7 +43,7 @@ function _interopNamespace(e) {
49
43
  return Object.freeze(n);
50
44
  }
51
45
 
52
- var React113__namespace = /*#__PURE__*/_interopNamespace(React113);
46
+ var React110__namespace = /*#__PURE__*/_interopNamespace(React110);
53
47
  var LucideIcons__namespace = /*#__PURE__*/_interopNamespace(LucideIcons);
54
48
  var L__default = /*#__PURE__*/_interopDefault(L);
55
49
  var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
@@ -58,12 +52,11 @@ var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
58
52
  var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
59
53
  var SyntaxHighlighter__default = /*#__PURE__*/_interopDefault(SyntaxHighlighter);
60
54
  var dark__default = /*#__PURE__*/_interopDefault(dark);
61
- var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
62
55
 
63
56
  var __defProp = Object.defineProperty;
64
57
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
65
58
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
66
- var EventBusContext = React113.createContext(null);
59
+ var EventBusContext = React110.createContext(null);
67
60
  function getGlobalEventBus() {
68
61
  if (typeof window !== "undefined") {
69
62
  return window.__kflowEventBus ?? null;
@@ -131,20 +124,11 @@ var fallbackEventBus = {
131
124
  }
132
125
  };
133
126
  function useEventBus() {
134
- const context = React113.useContext(EventBusContext);
127
+ const context = React110.useContext(EventBusContext);
135
128
  return context ?? getGlobalEventBus() ?? fallbackEventBus;
136
129
  }
137
- function useEmitEvent() {
138
- const eventBus = useEventBus();
139
- return React113.useCallback(
140
- (type, payload) => {
141
- eventBus.emit(type, payload);
142
- },
143
- [eventBus]
144
- );
145
- }
146
- React113.createContext(null);
147
- React113.createContext(null);
130
+ React110.createContext(null);
131
+ React110.createContext(null);
148
132
 
149
133
  // lib/api-client.ts
150
134
  typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "/api";
@@ -258,7 +242,7 @@ var en_default = {
258
242
  // hooks/useTranslate.ts
259
243
  var { $meta: _meta, ...coreMessages } = en_default;
260
244
  var coreLocale = coreMessages;
261
- var I18nContext = React113.createContext({
245
+ var I18nContext = React110.createContext({
262
246
  locale: "en",
263
247
  direction: "ltr",
264
248
  t: (key) => coreLocale[key] ?? key
@@ -267,13 +251,13 @@ var I18nContext = React113.createContext({
267
251
  I18nContext.displayName = "I18nContext";
268
252
  I18nContext.Provider;
269
253
  function useTranslate() {
270
- return React113.useContext(I18nContext);
254
+ return React110.useContext(I18nContext);
271
255
  }
272
256
  typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "http://localhost:3000";
273
- React113.createContext(void 0);
274
- var FetchedDataContext = React113.createContext(null);
257
+ React110.createContext(void 0);
258
+ var FetchedDataContext = React110.createContext(null);
275
259
  function useFetchedDataContext() {
276
- return React113.useContext(FetchedDataContext);
260
+ return React110.useContext(FetchedDataContext);
277
261
  }
278
262
  function cn(...inputs) {
279
263
  return tailwindMerge.twMerge(clsx.clsx(inputs));
@@ -415,7 +399,7 @@ var positionStyles = {
415
399
  fixed: "fixed",
416
400
  sticky: "sticky"
417
401
  };
418
- var Box = React113__namespace.default.forwardRef(
402
+ var Box = React110__namespace.default.forwardRef(
419
403
  ({
420
404
  padding,
421
405
  paddingX,
@@ -434,7 +418,7 @@ var Box = React113__namespace.default.forwardRef(
434
418
  position,
435
419
  className,
436
420
  children,
437
- as: Component2 = "div",
421
+ as: Component = "div",
438
422
  action,
439
423
  actionPayload,
440
424
  hoverEvent,
@@ -444,27 +428,27 @@ var Box = React113__namespace.default.forwardRef(
444
428
  ...rest
445
429
  }, ref) => {
446
430
  const eventBus = useEventBus();
447
- const handleClick = React113.useCallback((e) => {
431
+ const handleClick = React110.useCallback((e) => {
448
432
  if (action) {
449
433
  e.stopPropagation();
450
434
  eventBus.emit(`UI:${action}`, actionPayload ?? {});
451
435
  }
452
436
  onClick?.(e);
453
437
  }, [action, actionPayload, eventBus, onClick]);
454
- const handleMouseEnter = React113.useCallback((e) => {
438
+ const handleMouseEnter = React110.useCallback((e) => {
455
439
  if (hoverEvent) {
456
440
  eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
457
441
  }
458
442
  onMouseEnter?.(e);
459
443
  }, [hoverEvent, eventBus, onMouseEnter]);
460
- const handleMouseLeave = React113.useCallback((e) => {
444
+ const handleMouseLeave = React110.useCallback((e) => {
461
445
  if (hoverEvent) {
462
446
  eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
463
447
  }
464
448
  onMouseLeave?.(e);
465
449
  }, [hoverEvent, eventBus, onMouseLeave]);
466
450
  const isClickable = action || onClick;
467
- const Comp = Component2;
451
+ const Comp = Component;
468
452
  return /* @__PURE__ */ jsxRuntime.jsx(
469
453
  Comp,
470
454
  {
@@ -594,8 +578,8 @@ var Typography = ({
594
578
  children
595
579
  }) => {
596
580
  const variant = variantProp ?? (level ? `h${level}` : "body1");
597
- const Component2 = as || defaultElements[variant];
598
- const Comp = Component2;
581
+ const Component = as || defaultElements[variant];
582
+ const Comp = Component;
599
583
  return /* @__PURE__ */ jsxRuntime.jsx(
600
584
  Comp,
601
585
  {
@@ -685,7 +669,7 @@ function resolveIconProp(value, sizeClass) {
685
669
  const IconComp = value;
686
670
  return /* @__PURE__ */ jsxRuntime.jsx(IconComp, { className: sizeClass });
687
671
  }
688
- if (React113__namespace.default.isValidElement(value)) {
672
+ if (React110__namespace.default.isValidElement(value)) {
689
673
  return value;
690
674
  }
691
675
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -694,7 +678,7 @@ function resolveIconProp(value, sizeClass) {
694
678
  }
695
679
  return value;
696
680
  }
697
- var Button = React113__namespace.default.forwardRef(
681
+ var Button = React110__namespace.default.forwardRef(
698
682
  ({
699
683
  className,
700
684
  variant = "primary",
@@ -789,7 +773,7 @@ var sizeStyles3 = {
789
773
  md: "px-2.5 py-1 text-sm",
790
774
  lg: "px-3 py-1.5 text-base"
791
775
  };
792
- var Badge = React113__namespace.default.forwardRef(
776
+ var Badge = React110__namespace.default.forwardRef(
793
777
  ({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
794
778
  const iconSizes2 = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
795
779
  const resolvedIcon = typeof icon === "string" ? (() => {
@@ -816,7 +800,7 @@ var Badge = React113__namespace.default.forwardRef(
816
800
  }
817
801
  );
818
802
  Badge.displayName = "Badge";
819
- var Input = React113__namespace.default.forwardRef(
803
+ var Input = React110__namespace.default.forwardRef(
820
804
  ({
821
805
  className,
822
806
  inputType,
@@ -928,7 +912,7 @@ var Input = React113__namespace.default.forwardRef(
928
912
  }
929
913
  );
930
914
  Input.displayName = "Input";
931
- var Label = React113__namespace.default.forwardRef(
915
+ var Label = React110__namespace.default.forwardRef(
932
916
  ({ className, required, children, ...props }, ref) => {
933
917
  return /* @__PURE__ */ jsxRuntime.jsxs(
934
918
  "label",
@@ -948,7 +932,7 @@ var Label = React113__namespace.default.forwardRef(
948
932
  }
949
933
  );
950
934
  Label.displayName = "Label";
951
- var Textarea = React113__namespace.default.forwardRef(
935
+ var Textarea = React110__namespace.default.forwardRef(
952
936
  ({ className, error, ...props }, ref) => {
953
937
  return /* @__PURE__ */ jsxRuntime.jsx(
954
938
  "textarea",
@@ -971,7 +955,7 @@ var Textarea = React113__namespace.default.forwardRef(
971
955
  }
972
956
  );
973
957
  Textarea.displayName = "Textarea";
974
- var Select = React113__namespace.default.forwardRef(
958
+ var Select = React110__namespace.default.forwardRef(
975
959
  ({ className, options, placeholder, error, ...props }, ref) => {
976
960
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
977
961
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1007,7 +991,7 @@ var Select = React113__namespace.default.forwardRef(
1007
991
  }
1008
992
  );
1009
993
  Select.displayName = "Select";
1010
- var Checkbox = React113__namespace.default.forwardRef(
994
+ var Checkbox = React110__namespace.default.forwardRef(
1011
995
  ({ className, label, id, ...props }, ref) => {
1012
996
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
1013
997
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
@@ -1081,7 +1065,7 @@ var shadowStyles2 = {
1081
1065
  md: "shadow-[var(--shadow-main)]",
1082
1066
  lg: "shadow-[var(--shadow-lg)]"
1083
1067
  };
1084
- var Card = React113__namespace.default.forwardRef(
1068
+ var Card = React110__namespace.default.forwardRef(
1085
1069
  ({
1086
1070
  className,
1087
1071
  variant = "bordered",
@@ -1117,9 +1101,9 @@ var Card = React113__namespace.default.forwardRef(
1117
1101
  }
1118
1102
  );
1119
1103
  Card.displayName = "Card";
1120
- var CardHeader = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("mb-4", className), ...props }));
1104
+ var CardHeader = React110__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("mb-4", className), ...props }));
1121
1105
  CardHeader.displayName = "CardHeader";
1122
- var CardTitle = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1106
+ var CardTitle = React110__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1123
1107
  "h3",
1124
1108
  {
1125
1109
  ref,
@@ -1132,11 +1116,11 @@ var CardTitle = React113__namespace.default.forwardRef(({ className, ...props },
1132
1116
  }
1133
1117
  ));
1134
1118
  CardTitle.displayName = "CardTitle";
1135
- var CardContent = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("", className), ...props }));
1119
+ var CardContent = React110__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("", className), ...props }));
1136
1120
  CardContent.displayName = "CardContent";
1137
1121
  var CardBody = CardContent;
1138
1122
  CardBody.displayName = "CardBody";
1139
- var CardFooter = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1123
+ var CardFooter = React110__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1140
1124
  "div",
1141
1125
  {
1142
1126
  ref,
@@ -1151,7 +1135,7 @@ var sizeStyles4 = {
1151
1135
  md: "h-6 w-6",
1152
1136
  lg: "h-8 w-8"
1153
1137
  };
1154
- var Spinner = React113__namespace.default.forwardRef(
1138
+ var Spinner = React110__namespace.default.forwardRef(
1155
1139
  ({ className, size = "md", ...props }, ref) => {
1156
1140
  return /* @__PURE__ */ jsxRuntime.jsx(
1157
1141
  "div",
@@ -1165,7 +1149,7 @@ var Spinner = React113__namespace.default.forwardRef(
1165
1149
  }
1166
1150
  );
1167
1151
  Spinner.displayName = "Spinner";
1168
- var Radio = React113__namespace.default.forwardRef(
1152
+ var Radio = React110__namespace.default.forwardRef(
1169
1153
  ({
1170
1154
  label,
1171
1155
  helperText,
@@ -1269,7 +1253,7 @@ var Radio = React113__namespace.default.forwardRef(
1269
1253
  }
1270
1254
  );
1271
1255
  Radio.displayName = "Radio";
1272
- var Switch = React113__namespace.forwardRef(
1256
+ var Switch = React110__namespace.forwardRef(
1273
1257
  ({
1274
1258
  checked,
1275
1259
  defaultChecked = false,
@@ -1280,10 +1264,10 @@ var Switch = React113__namespace.forwardRef(
1280
1264
  name,
1281
1265
  className
1282
1266
  }, ref) => {
1283
- const [isChecked, setIsChecked] = React113__namespace.useState(
1267
+ const [isChecked, setIsChecked] = React110__namespace.useState(
1284
1268
  checked !== void 0 ? checked : defaultChecked
1285
1269
  );
1286
- React113__namespace.useEffect(() => {
1270
+ React110__namespace.useEffect(() => {
1287
1271
  if (checked !== void 0) {
1288
1272
  setIsChecked(checked);
1289
1273
  }
@@ -1377,7 +1361,7 @@ var Stack = ({
1377
1361
  className,
1378
1362
  style,
1379
1363
  children,
1380
- as: Component2 = "div",
1364
+ as: Component = "div",
1381
1365
  onClick,
1382
1366
  onKeyDown,
1383
1367
  role,
@@ -1395,7 +1379,7 @@ var Stack = ({
1395
1379
  };
1396
1380
  const isHorizontal = direction === "horizontal";
1397
1381
  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";
1398
- const Comp = Component2;
1382
+ const Comp = Component;
1399
1383
  return /* @__PURE__ */ jsxRuntime.jsx(
1400
1384
  Comp,
1401
1385
  {
@@ -1441,7 +1425,7 @@ var sizeStyles5 = {
1441
1425
  md: "w-2.5 h-2.5",
1442
1426
  lg: "w-3 h-3"
1443
1427
  };
1444
- var StatusDot = React113__namespace.default.forwardRef(
1428
+ var StatusDot = React110__namespace.default.forwardRef(
1445
1429
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
1446
1430
  return /* @__PURE__ */ jsxRuntime.jsx(
1447
1431
  "span",
@@ -1488,7 +1472,7 @@ var iconMap2 = {
1488
1472
  down: LucideIcons.TrendingDown,
1489
1473
  flat: LucideIcons.ArrowRight
1490
1474
  };
1491
- var TrendIndicator = React113__namespace.default.forwardRef(
1475
+ var TrendIndicator = React110__namespace.default.forwardRef(
1492
1476
  ({
1493
1477
  className,
1494
1478
  value,
@@ -1547,7 +1531,7 @@ var thumbSizes = {
1547
1531
  md: "w-4 h-4",
1548
1532
  lg: "w-5 h-5"
1549
1533
  };
1550
- var RangeSlider = React113__namespace.default.forwardRef(
1534
+ var RangeSlider = React110__namespace.default.forwardRef(
1551
1535
  ({
1552
1536
  className,
1553
1537
  min = 0,
@@ -1565,14 +1549,14 @@ var RangeSlider = React113__namespace.default.forwardRef(
1565
1549
  formatValue: formatValue5,
1566
1550
  ...props
1567
1551
  }, ref) => {
1568
- const [isDragging, setIsDragging] = React113.useState(false);
1569
- const [showTip, setShowTip] = React113.useState(false);
1570
- const inputRef = React113.useRef(null);
1552
+ const [isDragging, setIsDragging] = React110.useState(false);
1553
+ const [showTip, setShowTip] = React110.useState(false);
1554
+ const inputRef = React110.useRef(null);
1571
1555
  const eventBus = useSafeEventBus();
1572
1556
  const percentage = max !== min ? (value - min) / (max - min) * 100 : 0;
1573
1557
  const bufferedPercentage = buffered !== void 0 ? Math.min(buffered, 100) : void 0;
1574
1558
  const displayValue = formatValue5 ? formatValue5(value) : String(value);
1575
- const handleChange = React113.useCallback(
1559
+ const handleChange = React110.useCallback(
1576
1560
  (e) => {
1577
1561
  const newValue = Number(e.target.value);
1578
1562
  onChange?.(newValue);
@@ -1750,7 +1734,7 @@ var paddingClasses = {
1750
1734
  md: "py-16",
1751
1735
  lg: "py-24"
1752
1736
  };
1753
- var ContentSection = React113__namespace.default.forwardRef(
1737
+ var ContentSection = React110__namespace.default.forwardRef(
1754
1738
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
1755
1739
  return /* @__PURE__ */ jsxRuntime.jsx(
1756
1740
  Box,
@@ -1803,7 +1787,7 @@ var ErrorState = ({
1803
1787
  );
1804
1788
  };
1805
1789
  ErrorState.displayName = "ErrorState";
1806
- var ErrorBoundary = class extends React113__namespace.default.Component {
1790
+ var ErrorBoundary = class extends React110__namespace.default.Component {
1807
1791
  constructor(props) {
1808
1792
  super(props);
1809
1793
  __publicField(this, "reset", () => {
@@ -1844,9 +1828,9 @@ var ErrorBoundary = class extends React113__namespace.default.Component {
1844
1828
  }
1845
1829
  };
1846
1830
  __publicField(ErrorBoundary, "displayName", "ErrorBoundary");
1847
- var ClientEffectConfigContext = React113.createContext(null);
1831
+ var ClientEffectConfigContext = React110.createContext(null);
1848
1832
  ClientEffectConfigContext.Provider;
1849
- React113.createContext(null);
1833
+ React110.createContext(null);
1850
1834
  var defaultIcon = L__default.default.icon({
1851
1835
  iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
1852
1836
  iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
@@ -1978,7 +1962,7 @@ function waitForTransition(event, timeoutMs = 1e4) {
1978
1962
  });
1979
1963
  }
1980
1964
  exposeOnWindow();
1981
- var MarkdownContent = React113__namespace.default.memo(
1965
+ var MarkdownContent = React110__namespace.default.memo(
1982
1966
  ({ content, direction, className }) => {
1983
1967
  const { t: _t } = useTranslate();
1984
1968
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2079,7 +2063,7 @@ var MarkdownContent = React113__namespace.default.memo(
2079
2063
  (prev, next) => prev.content === next.content && prev.className === next.className && prev.direction === next.direction
2080
2064
  );
2081
2065
  MarkdownContent.displayName = "MarkdownContent";
2082
- var CodeBlock = React113__namespace.default.memo(
2066
+ var CodeBlock = React110__namespace.default.memo(
2083
2067
  ({
2084
2068
  code,
2085
2069
  language = "text",
@@ -2090,20 +2074,20 @@ var CodeBlock = React113__namespace.default.memo(
2090
2074
  }) => {
2091
2075
  const eventBus = useEventBus();
2092
2076
  const { t: _t } = useTranslate();
2093
- const scrollRef = React113.useRef(null);
2094
- const savedScrollLeftRef = React113.useRef(0);
2095
- const [copied, setCopied] = React113.useState(false);
2096
- React113.useLayoutEffect(() => {
2077
+ const scrollRef = React110.useRef(null);
2078
+ const savedScrollLeftRef = React110.useRef(0);
2079
+ const [copied, setCopied] = React110.useState(false);
2080
+ React110.useLayoutEffect(() => {
2097
2081
  const el = scrollRef.current;
2098
2082
  return () => {
2099
2083
  if (el) savedScrollLeftRef.current = el.scrollLeft;
2100
2084
  };
2101
2085
  }, [language, code]);
2102
- React113.useLayoutEffect(() => {
2086
+ React110.useLayoutEffect(() => {
2103
2087
  const el = scrollRef.current;
2104
2088
  if (el) el.scrollLeft = savedScrollLeftRef.current;
2105
2089
  }, [language, code]);
2106
- React113.useEffect(() => {
2090
+ React110.useEffect(() => {
2107
2091
  const el = scrollRef.current;
2108
2092
  if (!el) return;
2109
2093
  const handle = () => {
@@ -2186,1394 +2170,12 @@ var CodeBlock = React113__namespace.default.memo(
2186
2170
  (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight
2187
2171
  );
2188
2172
  CodeBlock.displayName = "CodeBlock";
2189
- var Camera3D = React113.forwardRef(
2190
- ({
2191
- mode = "isometric",
2192
- position = [10, 10, 10],
2193
- target = [0, 0, 0],
2194
- zoom = 1,
2195
- fov = 45,
2196
- enableOrbit = true,
2197
- minDistance = 2,
2198
- maxDistance = 100,
2199
- onChange
2200
- }, ref) => {
2201
- const { camera, set, viewport } = fiber.useThree();
2202
- const controlsRef = React113.useRef(null);
2203
- const initialPosition = React113.useRef(new THREE__namespace.Vector3(...position));
2204
- const initialTarget = React113.useRef(new THREE__namespace.Vector3(...target));
2205
- React113.useEffect(() => {
2206
- let newCamera;
2207
- if (mode === "isometric") {
2208
- const aspect = viewport.aspect;
2209
- const size = 10 / zoom;
2210
- newCamera = new THREE__namespace.OrthographicCamera(
2211
- -size * aspect,
2212
- size * aspect,
2213
- size,
2214
- -size,
2215
- 0.1,
2216
- 1e3
2217
- );
2218
- } else {
2219
- newCamera = new THREE__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
2220
- }
2221
- newCamera.position.copy(initialPosition.current);
2222
- newCamera.lookAt(initialTarget.current);
2223
- set({ camera: newCamera });
2224
- if (mode === "top-down") {
2225
- newCamera.position.set(0, 20 / zoom, 0);
2226
- newCamera.lookAt(0, 0, 0);
2227
- }
2228
- return () => {
2229
- };
2230
- }, [mode, fov, zoom, viewport.aspect, set]);
2231
- fiber.useFrame(() => {
2232
- if (onChange) {
2233
- onChange(camera);
2234
- }
2235
- });
2236
- React113.useImperativeHandle(ref, () => ({
2237
- getCamera: () => camera,
2238
- setPosition: (x, y, z) => {
2239
- camera.position.set(x, y, z);
2240
- if (controlsRef.current) {
2241
- controlsRef.current.update();
2242
- }
2243
- },
2244
- lookAt: (x, y, z) => {
2245
- camera.lookAt(x, y, z);
2246
- if (controlsRef.current) {
2247
- controlsRef.current.target.set(x, y, z);
2248
- controlsRef.current.update();
2249
- }
2250
- },
2251
- reset: () => {
2252
- camera.position.copy(initialPosition.current);
2253
- camera.lookAt(initialTarget.current);
2254
- if (controlsRef.current) {
2255
- controlsRef.current.target.copy(initialTarget.current);
2256
- controlsRef.current.update();
2257
- }
2258
- },
2259
- getViewBounds: () => {
2260
- const min = new THREE__namespace.Vector3(-10, -10, -10);
2261
- const max = new THREE__namespace.Vector3(10, 10, 10);
2262
- return { min, max };
2263
- }
2264
- }));
2265
- const maxPolarAngle = mode === "top-down" ? 0.1 : Math.PI / 2 - 0.1;
2266
- return /* @__PURE__ */ jsxRuntime.jsx(
2267
- drei.OrbitControls,
2268
- {
2269
- ref: controlsRef,
2270
- camera,
2271
- enabled: enableOrbit,
2272
- target: initialTarget.current,
2273
- minDistance,
2274
- maxDistance,
2275
- maxPolarAngle,
2276
- enableDamping: true,
2277
- dampingFactor: 0.05
2278
- }
2279
- );
2280
- }
2281
- );
2282
- Camera3D.displayName = "Camera3D";
2283
- var Canvas3DErrorBoundary = class extends React113.Component {
2284
- constructor(props) {
2285
- super(props);
2286
- __publicField(this, "handleReset", () => {
2287
- this.setState({
2288
- hasError: false,
2289
- error: null,
2290
- errorInfo: null
2291
- });
2292
- this.props.onReset?.();
2293
- });
2294
- this.state = {
2295
- hasError: false,
2296
- error: null,
2297
- errorInfo: null
2298
- };
2299
- }
2300
- static getDerivedStateFromError(error) {
2301
- return {
2302
- hasError: true,
2303
- error,
2304
- errorInfo: null
2305
- };
2306
- }
2307
- componentDidCatch(error, errorInfo) {
2308
- this.setState({ errorInfo });
2309
- this.props.onError?.(error, errorInfo);
2310
- console.error("[Canvas3DErrorBoundary] Error caught:", error);
2311
- console.error("[Canvas3DErrorBoundary] Component stack:", errorInfo.componentStack);
2312
- }
2313
- render() {
2314
- if (this.state.hasError) {
2315
- if (this.props.fallback) {
2316
- return this.props.fallback;
2317
- }
2318
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__content", children: [
2319
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
2320
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
2321
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
2322
- this.state.error && /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "canvas-3d-error__details", children: [
2323
- /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Error Details" }),
2324
- /* @__PURE__ */ jsxRuntime.jsxs("pre", { className: "error__stack", children: [
2325
- this.state.error.message,
2326
- "\n",
2327
- this.state.error.stack
2328
- ] }),
2329
- this.state.errorInfo && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
2330
- ] }),
2331
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__actions", children: [
2332
- /* @__PURE__ */ jsxRuntime.jsx(
2333
- "button",
2334
- {
2335
- className: "error__button error__button--primary",
2336
- onClick: this.handleReset,
2337
- children: "Try Again"
2338
- }
2339
- ),
2340
- /* @__PURE__ */ jsxRuntime.jsx(
2341
- "button",
2342
- {
2343
- className: "error__button error__button--secondary",
2344
- onClick: () => window.location.reload(),
2345
- children: "Reload Page"
2346
- }
2347
- )
2348
- ] })
2349
- ] }) });
2350
- }
2351
- return this.props.children;
2352
- }
2353
- };
2354
- function Canvas3DLoadingState({
2355
- progress = 0,
2356
- loaded = 0,
2357
- total = 0,
2358
- message = "Loading 3D Scene...",
2359
- details,
2360
- showSpinner = true,
2361
- className
2362
- }) {
2363
- const clampedProgress = Math.max(0, Math.min(100, progress));
2364
- const hasProgress = total > 0;
2365
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
2366
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__content", children: [
2367
- showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__spinner", children: [
2368
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring" }),
2369
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring spinner__ring--secondary" })
2370
- ] }),
2371
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__message", children: message }),
2372
- details && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__details", children: details }),
2373
- hasProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__progress", children: [
2374
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsxRuntime.jsx(
2375
- "div",
2376
- {
2377
- className: "progress__fill",
2378
- style: { width: `${clampedProgress}%` }
2379
- }
2380
- ) }),
2381
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "progress__text", children: [
2382
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__percentage", children: [
2383
- clampedProgress,
2384
- "%"
2385
- ] }),
2386
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__count", children: [
2387
- "(",
2388
- loaded,
2389
- "/",
2390
- total,
2391
- ")"
2392
- ] })
2393
- ] })
2394
- ] })
2395
- ] }),
2396
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg__grid" }) })
2397
- ] });
2398
- }
2399
2173
 
2400
2174
  // lib/debug.ts
2401
2175
  typeof window !== "undefined" && (localStorage.getItem("debug") === "true" || process.env.NODE_ENV === "development");
2402
- React113.lazy(() => import('react-markdown'));
2403
- var GameAudioContext = React113.createContext(null);
2176
+ React110.lazy(() => import('react-markdown'));
2177
+ var GameAudioContext = React110.createContext(null);
2404
2178
  GameAudioContext.displayName = "GameAudioContext";
2405
- function detectAssetRoot2(modelUrl) {
2406
- const idx = modelUrl.indexOf("/3d/");
2407
- if (idx !== -1) {
2408
- return modelUrl.substring(0, idx + 4);
2409
- }
2410
- return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
2411
- }
2412
- function createGLTFLoaderForUrl(url) {
2413
- const loader = new GLTFLoader_js.GLTFLoader();
2414
- loader.setResourcePath(detectAssetRoot2(url));
2415
- return loader;
2416
- }
2417
- var AssetLoader = class {
2418
- constructor() {
2419
- __publicField(this, "objLoader");
2420
- __publicField(this, "textureLoader");
2421
- __publicField(this, "modelCache");
2422
- __publicField(this, "textureCache");
2423
- __publicField(this, "loadingPromises");
2424
- this.objLoader = new OBJLoader_js.OBJLoader();
2425
- this.textureLoader = new THREE__namespace.TextureLoader();
2426
- this.modelCache = /* @__PURE__ */ new Map();
2427
- this.textureCache = /* @__PURE__ */ new Map();
2428
- this.loadingPromises = /* @__PURE__ */ new Map();
2429
- }
2430
- /**
2431
- * Load a GLB/GLTF model
2432
- * @param url - URL to the .glb or .gltf file
2433
- * @returns Promise with loaded model scene and animations
2434
- */
2435
- async loadModel(url) {
2436
- if (this.modelCache.has(url)) {
2437
- return this.modelCache.get(url);
2438
- }
2439
- if (this.loadingPromises.has(url)) {
2440
- return this.loadingPromises.get(url);
2441
- }
2442
- const loader = createGLTFLoaderForUrl(url);
2443
- const loadPromise = loader.loadAsync(url).then((gltf) => {
2444
- const result = {
2445
- scene: gltf.scene,
2446
- animations: gltf.animations || []
2447
- };
2448
- this.modelCache.set(url, result);
2449
- this.loadingPromises.delete(url);
2450
- return result;
2451
- }).catch((error) => {
2452
- this.loadingPromises.delete(url);
2453
- throw new Error(`Failed to load model ${url}: ${error.message}`);
2454
- });
2455
- this.loadingPromises.set(url, loadPromise);
2456
- return loadPromise;
2457
- }
2458
- /**
2459
- * Load an OBJ model (fallback for non-GLB assets)
2460
- * @param url - URL to the .obj file
2461
- * @returns Promise with loaded object group
2462
- */
2463
- async loadOBJ(url) {
2464
- if (this.modelCache.has(url)) {
2465
- return this.modelCache.get(url).scene;
2466
- }
2467
- if (this.loadingPromises.has(url)) {
2468
- const result = await this.loadingPromises.get(url);
2469
- return result.scene;
2470
- }
2471
- const loadPromise = this.objLoader.loadAsync(url).then((group) => {
2472
- const result = {
2473
- scene: group,
2474
- animations: []
2475
- };
2476
- this.modelCache.set(url, result);
2477
- this.loadingPromises.delete(url);
2478
- return result;
2479
- }).catch((error) => {
2480
- this.loadingPromises.delete(url);
2481
- throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
2482
- });
2483
- this.loadingPromises.set(url, loadPromise);
2484
- return (await loadPromise).scene;
2485
- }
2486
- /**
2487
- * Load a texture
2488
- * @param url - URL to the texture image
2489
- * @returns Promise with loaded texture
2490
- */
2491
- async loadTexture(url) {
2492
- if (this.textureCache.has(url)) {
2493
- return this.textureCache.get(url);
2494
- }
2495
- if (this.loadingPromises.has(`texture:${url}`)) {
2496
- return this.loadingPromises.get(`texture:${url}`);
2497
- }
2498
- const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
2499
- texture.colorSpace = THREE__namespace.SRGBColorSpace;
2500
- this.textureCache.set(url, texture);
2501
- this.loadingPromises.delete(`texture:${url}`);
2502
- return texture;
2503
- }).catch((error) => {
2504
- this.loadingPromises.delete(`texture:${url}`);
2505
- throw new Error(`Failed to load texture ${url}: ${error.message}`);
2506
- });
2507
- this.loadingPromises.set(`texture:${url}`, loadPromise);
2508
- return loadPromise;
2509
- }
2510
- /**
2511
- * Preload multiple assets
2512
- * @param urls - Array of asset URLs to preload
2513
- * @returns Promise that resolves when all assets are loaded
2514
- */
2515
- async preload(urls) {
2516
- const promises = urls.map((url) => {
2517
- if (url.endsWith(".glb") || url.endsWith(".gltf")) {
2518
- return this.loadModel(url).catch(() => null);
2519
- } else if (url.endsWith(".obj")) {
2520
- return this.loadOBJ(url).catch(() => null);
2521
- } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
2522
- return this.loadTexture(url).catch(() => null);
2523
- }
2524
- return Promise.resolve(null);
2525
- });
2526
- await Promise.all(promises);
2527
- }
2528
- /**
2529
- * Check if a model is cached
2530
- * @param url - Model URL
2531
- */
2532
- hasModel(url) {
2533
- return this.modelCache.has(url);
2534
- }
2535
- /**
2536
- * Check if a texture is cached
2537
- * @param url - Texture URL
2538
- */
2539
- hasTexture(url) {
2540
- return this.textureCache.has(url);
2541
- }
2542
- /**
2543
- * Get cached model (throws if not cached)
2544
- * @param url - Model URL
2545
- */
2546
- getModel(url) {
2547
- const model = this.modelCache.get(url);
2548
- if (!model) {
2549
- throw new Error(`Model ${url} not in cache`);
2550
- }
2551
- return model;
2552
- }
2553
- /**
2554
- * Get cached texture (throws if not cached)
2555
- * @param url - Texture URL
2556
- */
2557
- getTexture(url) {
2558
- const texture = this.textureCache.get(url);
2559
- if (!texture) {
2560
- throw new Error(`Texture ${url} not in cache`);
2561
- }
2562
- return texture;
2563
- }
2564
- /**
2565
- * Clear all caches
2566
- */
2567
- clearCache() {
2568
- this.textureCache.forEach((texture) => {
2569
- texture.dispose();
2570
- });
2571
- this.modelCache.forEach((model) => {
2572
- model.scene.traverse((child) => {
2573
- if (child instanceof THREE__namespace.Mesh) {
2574
- child.geometry.dispose();
2575
- if (Array.isArray(child.material)) {
2576
- child.material.forEach((m) => m.dispose());
2577
- } else {
2578
- child.material.dispose();
2579
- }
2580
- }
2581
- });
2582
- });
2583
- this.modelCache.clear();
2584
- this.textureCache.clear();
2585
- this.loadingPromises.clear();
2586
- }
2587
- /**
2588
- * Get cache statistics
2589
- */
2590
- getStats() {
2591
- return {
2592
- models: this.modelCache.size,
2593
- textures: this.textureCache.size,
2594
- loading: this.loadingPromises.size
2595
- };
2596
- }
2597
- };
2598
- new AssetLoader();
2599
- function useAssetLoader(options = {}) {
2600
- const { preloadUrls = [], loader: customLoader } = options;
2601
- const loaderRef = React113.useRef(customLoader || new AssetLoader());
2602
- const [state, setState] = React113.useState({
2603
- isLoading: false,
2604
- progress: 0,
2605
- loaded: 0,
2606
- total: 0,
2607
- errors: []
2608
- });
2609
- React113.useEffect(() => {
2610
- if (preloadUrls.length > 0) {
2611
- preload(preloadUrls);
2612
- }
2613
- }, []);
2614
- const updateProgress = React113.useCallback((loaded, total) => {
2615
- setState((prev) => ({
2616
- ...prev,
2617
- loaded,
2618
- total,
2619
- progress: total > 0 ? Math.round(loaded / total * 100) : 0
2620
- }));
2621
- }, []);
2622
- const loadModel = React113.useCallback(
2623
- async (url) => {
2624
- setState((prev) => ({ ...prev, isLoading: true }));
2625
- try {
2626
- const model = await loaderRef.current.loadModel(url);
2627
- setState((prev) => ({
2628
- ...prev,
2629
- isLoading: false,
2630
- loaded: prev.loaded + 1
2631
- }));
2632
- return model;
2633
- } catch (error) {
2634
- const errorMsg = error instanceof Error ? error.message : String(error);
2635
- setState((prev) => ({
2636
- ...prev,
2637
- isLoading: false,
2638
- errors: [...prev.errors, errorMsg]
2639
- }));
2640
- throw error;
2641
- }
2642
- },
2643
- []
2644
- );
2645
- const loadOBJ = React113.useCallback(
2646
- async (url) => {
2647
- setState((prev) => ({ ...prev, isLoading: true }));
2648
- try {
2649
- const model = await loaderRef.current.loadOBJ(url);
2650
- setState((prev) => ({
2651
- ...prev,
2652
- isLoading: false,
2653
- loaded: prev.loaded + 1
2654
- }));
2655
- return model;
2656
- } catch (error) {
2657
- const errorMsg = error instanceof Error ? error.message : String(error);
2658
- setState((prev) => ({
2659
- ...prev,
2660
- isLoading: false,
2661
- errors: [...prev.errors, errorMsg]
2662
- }));
2663
- throw error;
2664
- }
2665
- },
2666
- []
2667
- );
2668
- const loadTexture = React113.useCallback(
2669
- async (url) => {
2670
- setState((prev) => ({ ...prev, isLoading: true }));
2671
- try {
2672
- const texture = await loaderRef.current.loadTexture(url);
2673
- setState((prev) => ({
2674
- ...prev,
2675
- isLoading: false,
2676
- loaded: prev.loaded + 1
2677
- }));
2678
- return texture;
2679
- } catch (error) {
2680
- const errorMsg = error instanceof Error ? error.message : String(error);
2681
- setState((prev) => ({
2682
- ...prev,
2683
- isLoading: false,
2684
- errors: [...prev.errors, errorMsg]
2685
- }));
2686
- throw error;
2687
- }
2688
- },
2689
- []
2690
- );
2691
- const preload = React113.useCallback(
2692
- async (urls) => {
2693
- setState((prev) => ({
2694
- ...prev,
2695
- isLoading: true,
2696
- total: urls.length,
2697
- loaded: 0,
2698
- errors: []
2699
- }));
2700
- let completed = 0;
2701
- const errors = [];
2702
- await Promise.all(
2703
- urls.map(async (url) => {
2704
- try {
2705
- if (url.endsWith(".glb") || url.endsWith(".gltf")) {
2706
- await loaderRef.current.loadModel(url);
2707
- } else if (url.endsWith(".obj")) {
2708
- await loaderRef.current.loadOBJ(url);
2709
- } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
2710
- await loaderRef.current.loadTexture(url);
2711
- }
2712
- completed++;
2713
- updateProgress(completed, urls.length);
2714
- } catch (error) {
2715
- const errorMsg = error instanceof Error ? error.message : String(error);
2716
- errors.push(`${url}: ${errorMsg}`);
2717
- completed++;
2718
- updateProgress(completed, urls.length);
2719
- }
2720
- })
2721
- );
2722
- setState((prev) => ({
2723
- ...prev,
2724
- isLoading: false,
2725
- errors
2726
- }));
2727
- },
2728
- [updateProgress]
2729
- );
2730
- const hasModel = React113.useCallback((url) => {
2731
- return loaderRef.current.hasModel(url);
2732
- }, []);
2733
- const hasTexture = React113.useCallback((url) => {
2734
- return loaderRef.current.hasTexture(url);
2735
- }, []);
2736
- const getModel = React113.useCallback((url) => {
2737
- try {
2738
- return loaderRef.current.getModel(url);
2739
- } catch {
2740
- return void 0;
2741
- }
2742
- }, []);
2743
- const getTexture = React113.useCallback((url) => {
2744
- try {
2745
- return loaderRef.current.getTexture(url);
2746
- } catch {
2747
- return void 0;
2748
- }
2749
- }, []);
2750
- const clearCache = React113.useCallback(() => {
2751
- loaderRef.current.clearCache();
2752
- setState({
2753
- isLoading: false,
2754
- progress: 0,
2755
- loaded: 0,
2756
- total: 0,
2757
- errors: []
2758
- });
2759
- }, []);
2760
- return {
2761
- ...state,
2762
- loadModel,
2763
- loadOBJ,
2764
- loadTexture,
2765
- preload,
2766
- hasModel,
2767
- hasTexture,
2768
- getModel,
2769
- getTexture,
2770
- clearCache
2771
- };
2772
- }
2773
- function useGameCanvas3DEvents(options) {
2774
- const {
2775
- tileClickEvent,
2776
- unitClickEvent,
2777
- featureClickEvent,
2778
- canvasClickEvent,
2779
- tileHoverEvent,
2780
- tileLeaveEvent,
2781
- unitAnimationEvent,
2782
- cameraChangeEvent,
2783
- onTileClick,
2784
- onUnitClick,
2785
- onFeatureClick,
2786
- onCanvasClick,
2787
- onTileHover,
2788
- onUnitAnimation
2789
- } = options;
2790
- const emit = useEmitEvent();
2791
- const optionsRef = React113.useRef(options);
2792
- optionsRef.current = options;
2793
- const handleTileClick = React113.useCallback(
2794
- (tile, event) => {
2795
- if (tileClickEvent) {
2796
- emit(tileClickEvent, {
2797
- tileId: tile.id,
2798
- x: tile.x,
2799
- z: tile.z ?? tile.y ?? 0,
2800
- type: tile.type,
2801
- terrain: tile.terrain,
2802
- elevation: tile.elevation
2803
- });
2804
- }
2805
- optionsRef.current.onTileClick?.(tile, event);
2806
- },
2807
- [tileClickEvent, emit]
2808
- );
2809
- const handleUnitClick = React113.useCallback(
2810
- (unit, event) => {
2811
- if (unitClickEvent) {
2812
- emit(unitClickEvent, {
2813
- unitId: unit.id,
2814
- x: unit.x,
2815
- z: unit.z ?? unit.y ?? 0,
2816
- unitType: unit.unitType,
2817
- name: unit.name,
2818
- team: unit.team,
2819
- faction: unit.faction,
2820
- health: unit.health,
2821
- maxHealth: unit.maxHealth
2822
- });
2823
- }
2824
- optionsRef.current.onUnitClick?.(unit, event);
2825
- },
2826
- [unitClickEvent, emit]
2827
- );
2828
- const handleFeatureClick = React113.useCallback(
2829
- (feature, event) => {
2830
- if (featureClickEvent) {
2831
- emit(featureClickEvent, {
2832
- featureId: feature.id,
2833
- x: feature.x,
2834
- z: feature.z ?? feature.y ?? 0,
2835
- type: feature.type,
2836
- elevation: feature.elevation
2837
- });
2838
- }
2839
- optionsRef.current.onFeatureClick?.(feature, event);
2840
- },
2841
- [featureClickEvent, emit]
2842
- );
2843
- const handleCanvasClick = React113.useCallback(
2844
- (event) => {
2845
- if (canvasClickEvent) {
2846
- emit(canvasClickEvent, {
2847
- clientX: event.clientX,
2848
- clientY: event.clientY,
2849
- button: event.button
2850
- });
2851
- }
2852
- optionsRef.current.onCanvasClick?.(event);
2853
- },
2854
- [canvasClickEvent, emit]
2855
- );
2856
- const handleTileHover = React113.useCallback(
2857
- (tile, event) => {
2858
- if (tile) {
2859
- if (tileHoverEvent) {
2860
- emit(tileHoverEvent, {
2861
- tileId: tile.id,
2862
- x: tile.x,
2863
- z: tile.z ?? tile.y ?? 0,
2864
- type: tile.type
2865
- });
2866
- }
2867
- } else {
2868
- if (tileLeaveEvent) {
2869
- emit(tileLeaveEvent, {});
2870
- }
2871
- }
2872
- optionsRef.current.onTileHover?.(tile, event);
2873
- },
2874
- [tileHoverEvent, tileLeaveEvent, emit]
2875
- );
2876
- const handleUnitAnimation = React113.useCallback(
2877
- (unitId, state) => {
2878
- if (unitAnimationEvent) {
2879
- emit(unitAnimationEvent, {
2880
- unitId,
2881
- state,
2882
- timestamp: Date.now()
2883
- });
2884
- }
2885
- optionsRef.current.onUnitAnimation?.(unitId, state);
2886
- },
2887
- [unitAnimationEvent, emit]
2888
- );
2889
- const handleCameraChange = React113.useCallback(
2890
- (position) => {
2891
- if (cameraChangeEvent) {
2892
- emit(cameraChangeEvent, {
2893
- position,
2894
- timestamp: Date.now()
2895
- });
2896
- }
2897
- },
2898
- [cameraChangeEvent, emit]
2899
- );
2900
- return {
2901
- handleTileClick,
2902
- handleUnitClick,
2903
- handleFeatureClick,
2904
- handleCanvasClick,
2905
- handleTileHover,
2906
- handleUnitAnimation,
2907
- handleCameraChange
2908
- };
2909
- }
2910
- function detectAssetRoot3(modelUrl) {
2911
- const idx = modelUrl.indexOf("/3d/");
2912
- if (idx !== -1) {
2913
- return modelUrl.substring(0, idx + 4);
2914
- }
2915
- return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
2916
- }
2917
- function useGLTFModel2(url, resourceBasePath) {
2918
- const [state, setState] = React113.useState({
2919
- model: null,
2920
- isLoading: false,
2921
- error: null
2922
- });
2923
- React113.useEffect(() => {
2924
- if (!url) {
2925
- setState({ model: null, isLoading: false, error: null });
2926
- return;
2927
- }
2928
- console.log("[ModelLoader] Loading:", url);
2929
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
2930
- const assetRoot = resourceBasePath || detectAssetRoot3(url);
2931
- const loader = new GLTFLoader.GLTFLoader();
2932
- loader.setResourcePath(assetRoot);
2933
- loader.load(
2934
- url,
2935
- (gltf) => {
2936
- console.log("[ModelLoader] Loaded:", url);
2937
- setState({
2938
- model: gltf.scene,
2939
- isLoading: false,
2940
- error: null
2941
- });
2942
- },
2943
- void 0,
2944
- (err) => {
2945
- const errorMsg = err instanceof Error ? err.message : String(err);
2946
- console.warn("[ModelLoader] Failed:", url, errorMsg);
2947
- setState({
2948
- model: null,
2949
- isLoading: false,
2950
- error: err instanceof Error ? err : new Error(String(err))
2951
- });
2952
- }
2953
- );
2954
- }, [url, resourceBasePath]);
2955
- return state;
2956
- }
2957
- function ModelLoader({
2958
- url,
2959
- position = [0, 0, 0],
2960
- scale = 1,
2961
- rotation = [0, 0, 0],
2962
- isSelected = false,
2963
- isHovered = false,
2964
- onClick,
2965
- onHover,
2966
- fallbackGeometry = "box",
2967
- castShadow = true,
2968
- receiveShadow = true,
2969
- resourceBasePath
2970
- }) {
2971
- const { model: loadedModel, isLoading, error } = useGLTFModel2(url, resourceBasePath);
2972
- const model = React113.useMemo(() => {
2973
- if (!loadedModel) return null;
2974
- const cloned = loadedModel.clone();
2975
- cloned.traverse((child) => {
2976
- if (child instanceof THREE__namespace.Mesh) {
2977
- child.castShadow = castShadow;
2978
- child.receiveShadow = receiveShadow;
2979
- }
2980
- });
2981
- return cloned;
2982
- }, [loadedModel, castShadow, receiveShadow]);
2983
- const scaleArray = React113.useMemo(() => {
2984
- if (typeof scale === "number") {
2985
- return [scale, scale, scale];
2986
- }
2987
- return scale;
2988
- }, [scale]);
2989
- const rotationRad = React113.useMemo(() => {
2990
- return [
2991
- rotation[0] * Math.PI / 180,
2992
- rotation[1] * Math.PI / 180,
2993
- rotation[2] * Math.PI / 180
2994
- ];
2995
- }, [rotation]);
2996
- if (isLoading) {
2997
- return /* @__PURE__ */ jsxRuntime.jsx("group", { position, children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
2998
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
2999
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
3000
- ] }) });
3001
- }
3002
- if (error || !model) {
3003
- if (fallbackGeometry === "none") {
3004
- return /* @__PURE__ */ jsxRuntime.jsx("group", { position });
3005
- }
3006
- const fallbackProps = {
3007
- onClick,
3008
- onPointerOver: () => onHover?.(true),
3009
- onPointerOut: () => onHover?.(false)
3010
- };
3011
- return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
3012
- (isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
3013
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
3014
- /* @__PURE__ */ jsxRuntime.jsx(
3015
- "meshBasicMaterial",
3016
- {
3017
- color: isSelected ? 16755200 : 16777215,
3018
- transparent: true,
3019
- opacity: 0.5
3020
- }
3021
- )
3022
- ] }),
3023
- fallbackGeometry === "box" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
3024
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
3025
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
3026
- ] }),
3027
- fallbackGeometry === "sphere" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
3028
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.4, 16, 16] }),
3029
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
3030
- ] }),
3031
- fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
3032
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
3033
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
3034
- ] })
3035
- ] });
3036
- }
3037
- return /* @__PURE__ */ jsxRuntime.jsxs(
3038
- "group",
3039
- {
3040
- position,
3041
- rotation: rotationRad,
3042
- onClick,
3043
- onPointerOver: () => onHover?.(true),
3044
- onPointerOut: () => onHover?.(false),
3045
- children: [
3046
- (isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
3047
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
3048
- /* @__PURE__ */ jsxRuntime.jsx(
3049
- "meshBasicMaterial",
3050
- {
3051
- color: isSelected ? 16755200 : 16777215,
3052
- transparent: true,
3053
- opacity: 0.5
3054
- }
3055
- )
3056
- ] }),
3057
- /* @__PURE__ */ jsxRuntime.jsx("primitive", { object: model, scale: scaleArray })
3058
- ]
3059
- }
3060
- );
3061
- }
3062
- var DEFAULT_GRID_CONFIG = {
3063
- cellSize: 1,
3064
- offsetX: 0,
3065
- offsetZ: 0
3066
- };
3067
- function CameraController({
3068
- onCameraChange
3069
- }) {
3070
- const { camera } = fiber.useThree();
3071
- React113.useEffect(() => {
3072
- if (onCameraChange) {
3073
- onCameraChange({
3074
- x: camera.position.x,
3075
- y: camera.position.y,
3076
- z: camera.position.z
3077
- });
3078
- }
3079
- }, [camera.position, onCameraChange]);
3080
- return null;
3081
- }
3082
- var GameCanvas3D = React113.forwardRef(
3083
- ({
3084
- tiles = [],
3085
- units = [],
3086
- features = [],
3087
- events: events2 = [],
3088
- orientation = "standard",
3089
- cameraMode = "isometric",
3090
- showGrid = true,
3091
- showCoordinates = false,
3092
- showTileInfo = false,
3093
- overlay = "default",
3094
- shadows = true,
3095
- backgroundColor = "#1a1a2e",
3096
- onTileClick,
3097
- onUnitClick,
3098
- onFeatureClick,
3099
- onCanvasClick,
3100
- onTileHover,
3101
- onUnitAnimation,
3102
- assetLoader: customAssetLoader,
3103
- tileRenderer: CustomTileRenderer,
3104
- unitRenderer: CustomUnitRenderer,
3105
- featureRenderer: CustomFeatureRenderer,
3106
- className,
3107
- isLoading: externalLoading,
3108
- error: externalError,
3109
- entity,
3110
- preloadAssets = [],
3111
- tileClickEvent,
3112
- unitClickEvent,
3113
- featureClickEvent,
3114
- canvasClickEvent,
3115
- tileHoverEvent,
3116
- tileLeaveEvent,
3117
- unitAnimationEvent,
3118
- cameraChangeEvent,
3119
- loadingMessage = "Loading 3D Scene...",
3120
- useInstancing = true,
3121
- validMoves = [],
3122
- attackTargets = [],
3123
- selectedTileIds = [],
3124
- selectedUnitId = null,
3125
- children
3126
- }, ref) => {
3127
- const containerRef = React113.useRef(null);
3128
- const controlsRef = React113.useRef(null);
3129
- const [hoveredTile, setHoveredTile] = React113.useState(null);
3130
- const [internalError, setInternalError] = React113.useState(null);
3131
- const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
3132
- preloadUrls: preloadAssets,
3133
- loader: customAssetLoader
3134
- });
3135
- const eventHandlers = useGameCanvas3DEvents({
3136
- tileClickEvent,
3137
- unitClickEvent,
3138
- featureClickEvent,
3139
- canvasClickEvent,
3140
- tileHoverEvent,
3141
- tileLeaveEvent,
3142
- unitAnimationEvent,
3143
- cameraChangeEvent,
3144
- onTileClick,
3145
- onUnitClick,
3146
- onFeatureClick,
3147
- onCanvasClick,
3148
- onTileHover,
3149
- onUnitAnimation
3150
- });
3151
- const gridBounds = React113.useMemo(() => {
3152
- if (tiles.length === 0) {
3153
- return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
3154
- }
3155
- const xs = tiles.map((t) => t.x);
3156
- const zs = tiles.map((t) => t.z || t.y || 0);
3157
- return {
3158
- minX: Math.min(...xs),
3159
- maxX: Math.max(...xs),
3160
- minZ: Math.min(...zs),
3161
- maxZ: Math.max(...zs)
3162
- };
3163
- }, [tiles]);
3164
- const cameraTarget = React113.useMemo(() => {
3165
- return [
3166
- (gridBounds.minX + gridBounds.maxX) / 2,
3167
- 0,
3168
- (gridBounds.minZ + gridBounds.maxZ) / 2
3169
- ];
3170
- }, [gridBounds]);
3171
- const gridConfig = React113.useMemo(
3172
- () => ({
3173
- ...DEFAULT_GRID_CONFIG,
3174
- offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
3175
- offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
3176
- }),
3177
- [gridBounds]
3178
- );
3179
- const gridToWorld = React113.useCallback(
3180
- (x, z, y = 0) => {
3181
- const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
3182
- const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
3183
- return [worldX, y * gridConfig.cellSize, worldZ];
3184
- },
3185
- [gridBounds, gridConfig]
3186
- );
3187
- React113.useImperativeHandle(ref, () => ({
3188
- getCameraPosition: () => {
3189
- if (controlsRef.current) {
3190
- const pos = controlsRef.current.object.position;
3191
- return new THREE__namespace.Vector3(pos.x, pos.y, pos.z);
3192
- }
3193
- return null;
3194
- },
3195
- setCameraPosition: (x, y, z) => {
3196
- if (controlsRef.current) {
3197
- controlsRef.current.object.position.set(x, y, z);
3198
- controlsRef.current.update();
3199
- }
3200
- },
3201
- lookAt: (x, y, z) => {
3202
- if (controlsRef.current) {
3203
- controlsRef.current.target.set(x, y, z);
3204
- controlsRef.current.update();
3205
- }
3206
- },
3207
- resetCamera: () => {
3208
- if (controlsRef.current) {
3209
- controlsRef.current.reset();
3210
- }
3211
- },
3212
- screenshot: () => {
3213
- const canvas = containerRef.current?.querySelector("canvas");
3214
- if (canvas) {
3215
- return canvas.toDataURL("image/png");
3216
- }
3217
- return null;
3218
- },
3219
- export: () => ({
3220
- tiles,
3221
- units,
3222
- features
3223
- })
3224
- }));
3225
- const handleTileClick = React113.useCallback(
3226
- (tile, event) => {
3227
- eventHandlers.handleTileClick(tile, event);
3228
- },
3229
- [eventHandlers]
3230
- );
3231
- const handleUnitClick = React113.useCallback(
3232
- (unit, event) => {
3233
- eventHandlers.handleUnitClick(unit, event);
3234
- },
3235
- [eventHandlers]
3236
- );
3237
- const handleFeatureClick = React113.useCallback(
3238
- (feature, event) => {
3239
- if (event) {
3240
- eventHandlers.handleFeatureClick(feature, event);
3241
- }
3242
- },
3243
- [eventHandlers]
3244
- );
3245
- const handleTileHover = React113.useCallback(
3246
- (tile, event) => {
3247
- setHoveredTile(tile);
3248
- if (event) {
3249
- eventHandlers.handleTileHover(tile, event);
3250
- }
3251
- },
3252
- [eventHandlers]
3253
- );
3254
- const cameraConfig = React113.useMemo(() => {
3255
- const size = Math.max(
3256
- gridBounds.maxX - gridBounds.minX,
3257
- gridBounds.maxZ - gridBounds.minZ
3258
- );
3259
- const distance = size * 1.5;
3260
- switch (cameraMode) {
3261
- case "isometric":
3262
- return {
3263
- position: [distance, distance * 0.8, distance],
3264
- fov: 45
3265
- };
3266
- case "top-down":
3267
- return {
3268
- position: [0, distance * 2, 0],
3269
- fov: 45
3270
- };
3271
- case "perspective":
3272
- default:
3273
- return {
3274
- position: [distance, distance, distance],
3275
- fov: 45
3276
- };
3277
- }
3278
- }, [cameraMode, gridBounds]);
3279
- const DefaultTileRenderer = React113.useCallback(
3280
- ({ tile, position }) => {
3281
- const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
3282
- const isHovered = hoveredTile?.id === tile.id;
3283
- const isValidMove = validMoves.some(
3284
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
3285
- );
3286
- const isAttackTarget = attackTargets.some(
3287
- (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
3288
- );
3289
- let color = 8421504;
3290
- if (tile.type === "water") color = 4491468;
3291
- else if (tile.type === "grass") color = 4500036;
3292
- else if (tile.type === "sand") color = 14535816;
3293
- else if (tile.type === "rock") color = 8947848;
3294
- else if (tile.type === "snow") color = 15658734;
3295
- let emissive = 0;
3296
- if (isSelected) emissive = 4473924;
3297
- else if (isAttackTarget) emissive = 4456448;
3298
- else if (isValidMove) emissive = 17408;
3299
- else if (isHovered) emissive = 2236962;
3300
- return /* @__PURE__ */ jsxRuntime.jsxs(
3301
- "mesh",
3302
- {
3303
- position,
3304
- onClick: (e) => handleTileClick(tile, e),
3305
- onPointerEnter: (e) => handleTileHover(tile, e),
3306
- onPointerLeave: (e) => handleTileHover(null, e),
3307
- userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
3308
- children: [
3309
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
3310
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, emissive })
3311
- ]
3312
- }
3313
- );
3314
- },
3315
- [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
3316
- );
3317
- const DefaultUnitRenderer = React113.useCallback(
3318
- ({ unit, position }) => {
3319
- const isSelected = selectedUnitId === unit.id;
3320
- const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
3321
- return /* @__PURE__ */ jsxRuntime.jsxs(
3322
- "group",
3323
- {
3324
- position,
3325
- onClick: (e) => handleUnitClick(unit, e),
3326
- userData: { type: "unit", unitId: unit.id },
3327
- children: [
3328
- isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
3329
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
3330
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
3331
- ] }),
3332
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
3333
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
3334
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
3335
- ] }),
3336
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
3337
- /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
3338
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
3339
- ] }),
3340
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
3341
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
3342
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
3343
- ] }),
3344
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
3345
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
3346
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
3347
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
3348
- ] }),
3349
- /* @__PURE__ */ jsxRuntime.jsxs(
3350
- "mesh",
3351
- {
3352
- position: [
3353
- -0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
3354
- 0,
3355
- 0.01
3356
- ],
3357
- children: [
3358
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
3359
- /* @__PURE__ */ jsxRuntime.jsx(
3360
- "meshBasicMaterial",
3361
- {
3362
- color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
3363
- }
3364
- )
3365
- ]
3366
- }
3367
- )
3368
- ] })
3369
- ]
3370
- }
3371
- );
3372
- },
3373
- [selectedUnitId, handleUnitClick]
3374
- );
3375
- const DefaultFeatureRenderer = React113.useCallback(
3376
- ({
3377
- feature,
3378
- position
3379
- }) => {
3380
- if (feature.assetUrl) {
3381
- return /* @__PURE__ */ jsxRuntime.jsx(
3382
- ModelLoader,
3383
- {
3384
- url: feature.assetUrl,
3385
- position,
3386
- scale: 0.5,
3387
- rotation: [0, feature.rotation ?? 0, 0],
3388
- onClick: () => handleFeatureClick(feature, null),
3389
- fallbackGeometry: "box"
3390
- },
3391
- feature.id
3392
- );
3393
- }
3394
- if (feature.type === "tree") {
3395
- return /* @__PURE__ */ jsxRuntime.jsxs(
3396
- "group",
3397
- {
3398
- position,
3399
- onClick: (e) => handleFeatureClick(feature, e),
3400
- userData: { type: "feature", featureId: feature.id },
3401
- children: [
3402
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.4, 0], children: [
3403
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
3404
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 9127187 })
3405
- ] }),
3406
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
3407
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
3408
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 2263842 })
3409
- ] })
3410
- ]
3411
- }
3412
- );
3413
- }
3414
- if (feature.type === "rock") {
3415
- return /* @__PURE__ */ jsxRuntime.jsxs(
3416
- "mesh",
3417
- {
3418
- position: [position[0], position[1] + 0.3, position[2]],
3419
- onClick: (e) => handleFeatureClick(feature, e),
3420
- userData: { type: "feature", featureId: feature.id },
3421
- children: [
3422
- /* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [0.3, 0] }),
3423
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 8421504 })
3424
- ]
3425
- }
3426
- );
3427
- }
3428
- return null;
3429
- },
3430
- [handleFeatureClick]
3431
- );
3432
- if (externalLoading || assetsLoading && preloadAssets.length > 0) {
3433
- return /* @__PURE__ */ jsxRuntime.jsx(
3434
- Canvas3DLoadingState,
3435
- {
3436
- progress,
3437
- loaded,
3438
- total,
3439
- message: loadingMessage,
3440
- className
3441
- }
3442
- );
3443
- }
3444
- const displayError = externalError || internalError;
3445
- if (displayError) {
3446
- 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: [
3447
- "Error: ",
3448
- displayError
3449
- ] }) }) });
3450
- }
3451
- return /* @__PURE__ */ jsxRuntime.jsx(
3452
- Canvas3DErrorBoundary,
3453
- {
3454
- onError: (err) => setInternalError(err.message),
3455
- onReset: () => setInternalError(null),
3456
- children: /* @__PURE__ */ jsxRuntime.jsxs(
3457
- "div",
3458
- {
3459
- ref: containerRef,
3460
- className: `game-canvas-3d ${className || ""}`,
3461
- "data-orientation": orientation,
3462
- "data-camera-mode": cameraMode,
3463
- "data-overlay": overlay,
3464
- children: [
3465
- /* @__PURE__ */ jsxRuntime.jsxs(
3466
- fiber.Canvas,
3467
- {
3468
- shadows,
3469
- camera: {
3470
- position: cameraConfig.position,
3471
- fov: cameraConfig.fov,
3472
- near: 0.1,
3473
- far: 1e3
3474
- },
3475
- style: { background: backgroundColor },
3476
- onClick: (e) => {
3477
- if (e.target === e.currentTarget) {
3478
- eventHandlers.handleCanvasClick(e);
3479
- }
3480
- },
3481
- children: [
3482
- /* @__PURE__ */ jsxRuntime.jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
3483
- /* @__PURE__ */ jsxRuntime.jsx("ambientLight", { intensity: 0.6 }),
3484
- /* @__PURE__ */ jsxRuntime.jsx(
3485
- "directionalLight",
3486
- {
3487
- position: [10, 20, 10],
3488
- intensity: 0.8,
3489
- castShadow: shadows,
3490
- "shadow-mapSize": [2048, 2048]
3491
- }
3492
- ),
3493
- /* @__PURE__ */ jsxRuntime.jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
3494
- showGrid && /* @__PURE__ */ jsxRuntime.jsx(
3495
- drei.Grid,
3496
- {
3497
- args: [
3498
- Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
3499
- Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
3500
- ],
3501
- position: [
3502
- (gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
3503
- 0,
3504
- (gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
3505
- ],
3506
- cellSize: 1,
3507
- cellThickness: 1,
3508
- cellColor: "#444444",
3509
- sectionSize: 5,
3510
- sectionThickness: 1.5,
3511
- sectionColor: "#666666",
3512
- fadeDistance: 50,
3513
- fadeStrength: 1
3514
- }
3515
- ),
3516
- tiles.map((tile, index) => {
3517
- const position = gridToWorld(
3518
- tile.x,
3519
- tile.z ?? tile.y ?? 0,
3520
- tile.elevation ?? 0
3521
- );
3522
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
3523
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
3524
- }),
3525
- features.map((feature, index) => {
3526
- const position = gridToWorld(
3527
- feature.x,
3528
- feature.z ?? feature.y ?? 0,
3529
- (feature.elevation ?? 0) + 0.5
3530
- );
3531
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
3532
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
3533
- }),
3534
- units.map((unit) => {
3535
- const position = gridToWorld(
3536
- unit.x ?? 0,
3537
- unit.z ?? unit.y ?? 0,
3538
- (unit.elevation ?? 0) + 0.5
3539
- );
3540
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
3541
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
3542
- }),
3543
- children,
3544
- /* @__PURE__ */ jsxRuntime.jsx(
3545
- drei.OrbitControls,
3546
- {
3547
- ref: controlsRef,
3548
- target: cameraTarget,
3549
- enableDamping: true,
3550
- dampingFactor: 0.05,
3551
- minDistance: 2,
3552
- maxDistance: 100,
3553
- maxPolarAngle: Math.PI / 2 - 0.1
3554
- }
3555
- )
3556
- ]
3557
- }
3558
- ),
3559
- showCoordinates && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__coordinates", children: [
3560
- "X: ",
3561
- hoveredTile.x,
3562
- ", Z: ",
3563
- hoveredTile.z ?? hoveredTile.y ?? 0
3564
- ] }),
3565
- showTileInfo && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__tile-info", children: [
3566
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
3567
- hoveredTile.terrain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
3568
- ] })
3569
- ]
3570
- }
3571
- )
3572
- }
3573
- );
3574
- }
3575
- );
3576
- GameCanvas3D.displayName = "GameCanvas3D";
3577
2179
 
3578
2180
  // lib/traitRegistry.ts
3579
2181
  var traits = /* @__PURE__ */ new Map();
@@ -3597,9 +2199,38 @@ function unregisterTrait(id) {
3597
2199
  traits.delete(id);
3598
2200
  notifyListeners2();
3599
2201
  }
3600
- React113.createContext({ enabled: false });
3601
- React113.createContext(false);
3602
- React113.createContext(null);
2202
+
2203
+ // components/organisms/component-registry.generated.ts
2204
+ function lazyThree(name, loader) {
2205
+ const Lazy = React110__namespace.default.lazy(() => loader().then((m) => ({ default: m[name] })));
2206
+ function ThreeWrapper(props) {
2207
+ return React110__namespace.default.createElement(
2208
+ React110__namespace.default.Suspense,
2209
+ { fallback: null },
2210
+ React110__namespace.default.createElement(Lazy, props)
2211
+ );
2212
+ }
2213
+ ThreeWrapper.displayName = `Lazy(${name})`;
2214
+ return ThreeWrapper;
2215
+ }
2216
+ lazyThree("Camera3D", () => import('@almadar/ui/components/organisms/game/three'));
2217
+ lazyThree("Canvas3DErrorBoundary", () => import('@almadar/ui/components/organisms/game/three'));
2218
+ lazyThree("Canvas3DLoadingState", () => import('@almadar/ui/components/organisms/game/three'));
2219
+ lazyThree("FeatureRenderer", () => import('@almadar/ui/components/organisms/game/three'));
2220
+ lazyThree("FeatureRenderer3D", () => import('@almadar/ui/components/organisms/game/three'));
2221
+ lazyThree("GameCanvas3D", () => import('@almadar/ui/components/organisms/game/three'));
2222
+ lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/organisms/game/three'));
2223
+ lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/organisms/game/three'));
2224
+ lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/organisms/game/three'));
2225
+ lazyThree("Lighting3D", () => import('@almadar/ui/components/organisms/game/three'));
2226
+ lazyThree("ModelLoader", () => import('@almadar/ui/components/organisms/game/three'));
2227
+ lazyThree("PhysicsObject3D", () => import('@almadar/ui/components/organisms/game/three'));
2228
+ lazyThree("Scene3D", () => import('@almadar/ui/components/organisms/game/three'));
2229
+ lazyThree("TileRenderer", () => import('@almadar/ui/components/organisms/game/three'));
2230
+ lazyThree("UnitRenderer", () => import('@almadar/ui/components/organisms/game/three'));
2231
+ React110.createContext({ enabled: false });
2232
+ React110.createContext(false);
2233
+ React110.createContext(null);
3603
2234
 
3604
2235
  // runtime/createClientEffectHandlers.ts
3605
2236
  function createClientEffectHandlers(options) {
@@ -3635,19 +2266,19 @@ function createClientEffectHandlers(options) {
3635
2266
  })
3636
2267
  };
3637
2268
  }
3638
- var EntitySchemaContext = React113.createContext(null);
2269
+ var EntitySchemaContext = React110.createContext(null);
3639
2270
  function EntitySchemaProvider({
3640
2271
  entities,
3641
2272
  children
3642
2273
  }) {
3643
- const entitiesMap = React113.useMemo(() => {
2274
+ const entitiesMap = React110.useMemo(() => {
3644
2275
  const map = /* @__PURE__ */ new Map();
3645
2276
  for (const entity of entities) {
3646
2277
  map.set(entity.name, entity);
3647
2278
  }
3648
2279
  return map;
3649
2280
  }, [entities]);
3650
- const contextValue = React113.useMemo(
2281
+ const contextValue = React110.useMemo(
3651
2282
  () => ({
3652
2283
  entities: entitiesMap
3653
2284
  }),
@@ -3656,7 +2287,7 @@ function EntitySchemaProvider({
3656
2287
  return /* @__PURE__ */ jsxRuntime.jsx(EntitySchemaContext.Provider, { value: contextValue, children });
3657
2288
  }
3658
2289
  function useEntitySchema() {
3659
- const context = React113.useContext(EntitySchemaContext);
2290
+ const context = React110.useContext(EntitySchemaContext);
3660
2291
  if (!context) {
3661
2292
  throw new Error("useEntitySchema must be used within an EntitySchemaProvider");
3662
2293
  }
@@ -3683,41 +2314,41 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
3683
2314
  const eventBus = useEventBus();
3684
2315
  const { entities } = useEntitySchema();
3685
2316
  const fetchedDataContext = useFetchedDataContext();
3686
- const manager = React113.useMemo(() => {
2317
+ const manager = React110.useMemo(() => {
3687
2318
  const traitDefs = traitBindings.map(toTraitDefinition);
3688
2319
  return new runtime.StateMachineManager(traitDefs);
3689
2320
  }, [traitBindings]);
3690
- const [traitStates, setTraitStates] = React113.useState(() => {
2321
+ const [traitStates, setTraitStates] = React110.useState(() => {
3691
2322
  return manager.getAllStates();
3692
2323
  });
3693
- const eventQueueRef = React113.useRef([]);
3694
- const processingRef = React113.useRef(false);
3695
- const traitBindingsRef = React113.useRef(traitBindings);
3696
- const managerRef = React113.useRef(manager);
3697
- const slotsActionsRef = React113.useRef(slotsActions);
3698
- const optionsRef = React113.useRef(options);
3699
- React113.useEffect(() => {
2324
+ const eventQueueRef = React110.useRef([]);
2325
+ const processingRef = React110.useRef(false);
2326
+ const traitBindingsRef = React110.useRef(traitBindings);
2327
+ const managerRef = React110.useRef(manager);
2328
+ const slotsActionsRef = React110.useRef(slotsActions);
2329
+ const optionsRef = React110.useRef(options);
2330
+ React110.useEffect(() => {
3700
2331
  traitBindingsRef.current = traitBindings;
3701
2332
  }, [traitBindings]);
3702
- React113.useEffect(() => {
2333
+ React110.useEffect(() => {
3703
2334
  managerRef.current = manager;
3704
2335
  setTraitStates(manager.getAllStates());
3705
2336
  }, [manager]);
3706
- React113.useEffect(() => {
2337
+ React110.useEffect(() => {
3707
2338
  slotsActionsRef.current = slotsActions;
3708
2339
  }, [slotsActions]);
3709
- React113.useEffect(() => {
2340
+ React110.useEffect(() => {
3710
2341
  optionsRef.current = options;
3711
2342
  }, [options]);
3712
- const traitStatesRef = React113.useRef(traitStates);
3713
- const fetchedDataContextRef = React113.useRef(fetchedDataContext);
3714
- React113.useEffect(() => {
2343
+ const traitStatesRef = React110.useRef(traitStates);
2344
+ const fetchedDataContextRef = React110.useRef(fetchedDataContext);
2345
+ React110.useEffect(() => {
3715
2346
  traitStatesRef.current = traitStates;
3716
2347
  }, [traitStates]);
3717
- React113.useEffect(() => {
2348
+ React110.useEffect(() => {
3718
2349
  fetchedDataContextRef.current = fetchedDataContext;
3719
2350
  }, [fetchedDataContext]);
3720
- React113.useEffect(() => {
2351
+ React110.useEffect(() => {
3721
2352
  const mgr = managerRef.current;
3722
2353
  const bindings = traitBindingsRef.current;
3723
2354
  const ids = [];
@@ -3750,7 +2381,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
3750
2381
  }
3751
2382
  };
3752
2383
  }, [traitBindings]);
3753
- React113.useEffect(() => {
2384
+ React110.useEffect(() => {
3754
2385
  const newManager = managerRef.current;
3755
2386
  newManager.resetAll();
3756
2387
  setTraitStates(newManager.getAllStates());
@@ -3759,7 +2390,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
3759
2390
  Array.from(newManager.getAllStates().keys()).join(", ")
3760
2391
  );
3761
2392
  }, [traitBindings]);
3762
- const runTickEffects = React113.useCallback((tick, binding) => {
2393
+ const runTickEffects = React110.useCallback((tick, binding) => {
3763
2394
  const fdc = fetchedDataContextRef.current;
3764
2395
  const actions = slotsActionsRef.current;
3765
2396
  const linkedEntity = binding.linkedEntity ?? "";
@@ -3858,7 +2489,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
3858
2489
  }
3859
2490
  }
3860
2491
  }, []);
3861
- React113.useEffect(() => {
2492
+ React110.useEffect(() => {
3862
2493
  const hasFrameTicks = traitBindingsRef.current.some(
3863
2494
  (b) => b.trait.ticks?.some((t) => t.interval === "frame")
3864
2495
  );
@@ -3881,7 +2512,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
3881
2512
  cancelAnimationFrame(rafId);
3882
2513
  };
3883
2514
  }, [traitBindings, runTickEffects]);
3884
- React113.useEffect(() => {
2515
+ React110.useEffect(() => {
3885
2516
  const intervals = [];
3886
2517
  for (const binding of traitBindings) {
3887
2518
  for (const tick of binding.trait.ticks ?? []) {
@@ -3896,7 +2527,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
3896
2527
  for (const id of intervals) clearInterval(id);
3897
2528
  };
3898
2529
  }, [traitBindings, runTickEffects]);
3899
- const processEventQueued = React113.useCallback(async (eventKey, payload) => {
2530
+ const processEventQueued = React110.useCallback(async (eventKey, payload) => {
3900
2531
  const normalizedEvent = normalizeEventKey(eventKey);
3901
2532
  const bindings = traitBindingsRef.current;
3902
2533
  const currentManager = managerRef.current;
@@ -4163,7 +2794,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
4163
2794
  onEventProcessed(normalizedEvent, payload);
4164
2795
  }
4165
2796
  }, [entities, fetchedDataContext, eventBus]);
4166
- const drainEventQueue = React113.useCallback(async () => {
2797
+ const drainEventQueue = React110.useCallback(async () => {
4167
2798
  if (processingRef.current) return;
4168
2799
  processingRef.current = true;
4169
2800
  try {
@@ -4175,24 +2806,24 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
4175
2806
  processingRef.current = false;
4176
2807
  }
4177
2808
  }, [processEventQueued]);
4178
- const enqueueAndDrain = React113.useCallback((eventKey, payload) => {
2809
+ const enqueueAndDrain = React110.useCallback((eventKey, payload) => {
4179
2810
  eventQueueRef.current.push({ eventKey, payload });
4180
2811
  void drainEventQueue();
4181
2812
  }, [drainEventQueue]);
4182
- React113.useCallback((eventKey, payload) => {
2813
+ React110.useCallback((eventKey, payload) => {
4183
2814
  enqueueAndDrain(eventKey, payload);
4184
2815
  }, [enqueueAndDrain]);
4185
- const sendEvent = React113.useCallback((eventKey, payload) => {
2816
+ const sendEvent = React110.useCallback((eventKey, payload) => {
4186
2817
  enqueueAndDrain(eventKey, payload);
4187
2818
  }, [enqueueAndDrain]);
4188
- const getTraitState = React113.useCallback((traitName) => {
2819
+ const getTraitState = React110.useCallback((traitName) => {
4189
2820
  return managerRef.current.getState(traitName);
4190
2821
  }, []);
4191
- const canHandleEvent = React113.useCallback((traitName, eventKey) => {
2822
+ const canHandleEvent = React110.useCallback((traitName, eventKey) => {
4192
2823
  const normalizedEvent = normalizeEventKey(eventKey);
4193
2824
  return managerRef.current.canHandleEvent(traitName, normalizedEvent);
4194
2825
  }, []);
4195
- React113.useEffect(() => {
2826
+ React110.useEffect(() => {
4196
2827
  const allEvents = /* @__PURE__ */ new Set();
4197
2828
  for (const binding of traitBindings) {
4198
2829
  for (const event of binding.trait.events) {
@@ -4228,9 +2859,9 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
4228
2859
  };
4229
2860
  }
4230
2861
  function useResolvedSchema(schema, pageName) {
4231
- const [loading, setLoading] = React113.useState(true);
4232
- const [error, setError] = React113.useState(null);
4233
- const ir = React113.useMemo(() => {
2862
+ const [loading, setLoading] = React110.useState(true);
2863
+ const [error, setError] = React110.useState(null);
2864
+ const ir = React110.useMemo(() => {
4234
2865
  if (!schema) return null;
4235
2866
  try {
4236
2867
  return core.schemaToIR(schema);
@@ -4239,10 +2870,10 @@ function useResolvedSchema(schema, pageName) {
4239
2870
  return null;
4240
2871
  }
4241
2872
  }, [schema]);
4242
- React113.useEffect(() => {
2873
+ React110.useEffect(() => {
4243
2874
  setLoading(false);
4244
2875
  }, [ir]);
4245
- const result = React113.useMemo(() => {
2876
+ const result = React110.useMemo(() => {
4246
2877
  if (!ir) {
4247
2878
  return {
4248
2879
  page: void 0,
@@ -4280,12 +2911,12 @@ function useResolvedSchema(schema, pageName) {
4280
2911
  function clearSchemaCache() {
4281
2912
  core.clearSchemaCache();
4282
2913
  }
4283
- var TraitContext = React113.createContext(null);
2914
+ var TraitContext = React110.createContext(null);
4284
2915
  function TraitProvider({
4285
2916
  traits: traitBindings,
4286
2917
  children
4287
2918
  }) {
4288
- const traitInstances = React113.useMemo(() => {
2919
+ const traitInstances = React110.useMemo(() => {
4289
2920
  const map = /* @__PURE__ */ new Map();
4290
2921
  for (const binding of traitBindings) {
4291
2922
  const trait = binding.trait;
@@ -4309,7 +2940,7 @@ function TraitProvider({
4309
2940
  }
4310
2941
  return map;
4311
2942
  }, [traitBindings]);
4312
- const contextValue = React113.useMemo(() => {
2943
+ const contextValue = React110.useMemo(() => {
4313
2944
  return {
4314
2945
  traits: traitInstances,
4315
2946
  getTrait: (name) => traitInstances.get(name),
@@ -4328,7 +2959,7 @@ function TraitProvider({
4328
2959
  return /* @__PURE__ */ jsxRuntime.jsx(TraitContext.Provider, { value: contextValue, children });
4329
2960
  }
4330
2961
  function useTraitContext() {
4331
- const context = React113.useContext(TraitContext);
2962
+ const context = React110.useContext(TraitContext);
4332
2963
  if (!context) {
4333
2964
  throw new Error("useTraitContext must be used within a TraitProvider");
4334
2965
  }
@@ -4338,17 +2969,17 @@ function useTrait(traitName) {
4338
2969
  const context = useTraitContext();
4339
2970
  return context.getTrait(traitName);
4340
2971
  }
4341
- var SlotsStateContext = React113.createContext({});
4342
- var SlotsActionsContext = React113.createContext(null);
2972
+ var SlotsStateContext = React110.createContext({});
2973
+ var SlotsActionsContext = React110.createContext(null);
4343
2974
  function SlotsProvider({ children }) {
4344
- const [slots, setSlots] = React113.useState({});
4345
- const setSlotPatterns = React113.useCallback((slot, patterns, source) => {
2975
+ const [slots, setSlots] = React110.useState({});
2976
+ const setSlotPatterns = React110.useCallback((slot, patterns, source) => {
4346
2977
  setSlots((prev) => ({
4347
2978
  ...prev,
4348
2979
  [slot]: { patterns, source }
4349
2980
  }));
4350
2981
  }, []);
4351
- const clearSlot = React113.useCallback((slot) => {
2982
+ const clearSlot = React110.useCallback((slot) => {
4352
2983
  setSlots((prev) => {
4353
2984
  if (!(slot in prev)) return prev;
4354
2985
  const next = { ...prev };
@@ -4356,12 +2987,12 @@ function SlotsProvider({ children }) {
4356
2987
  return next;
4357
2988
  });
4358
2989
  }, []);
4359
- const clearAllSlots = React113.useCallback(() => {
2990
+ const clearAllSlots = React110.useCallback(() => {
4360
2991
  setSlots({});
4361
2992
  }, []);
4362
- const actionsRef = React113.useRef({ setSlotPatterns, clearSlot, clearAllSlots });
2993
+ const actionsRef = React110.useRef({ setSlotPatterns, clearSlot, clearAllSlots });
4363
2994
  actionsRef.current = { setSlotPatterns, clearSlot, clearAllSlots };
4364
- const [stableActions] = React113.useState(() => ({
2995
+ const [stableActions] = React110.useState(() => ({
4365
2996
  setSlotPatterns: (...args) => actionsRef.current.setSlotPatterns(...args),
4366
2997
  clearSlot: (...args) => actionsRef.current.clearSlot(...args),
4367
2998
  clearAllSlots: () => actionsRef.current.clearAllSlots()
@@ -4369,14 +3000,14 @@ function SlotsProvider({ children }) {
4369
3000
  return /* @__PURE__ */ jsxRuntime.jsx(SlotsActionsContext.Provider, { value: stableActions, children: /* @__PURE__ */ jsxRuntime.jsx(SlotsStateContext.Provider, { value: slots, children }) });
4370
3001
  }
4371
3002
  function useSlots() {
4372
- return React113.useContext(SlotsStateContext);
3003
+ return React110.useContext(SlotsStateContext);
4373
3004
  }
4374
3005
  function useSlotContent(slotName) {
4375
- const slots = React113.useContext(SlotsStateContext);
3006
+ const slots = React110.useContext(SlotsStateContext);
4376
3007
  return slots[slotName] || null;
4377
3008
  }
4378
3009
  function useSlotsActions() {
4379
- const actions = React113.useContext(SlotsActionsContext);
3010
+ const actions = React110.useContext(SlotsActionsContext);
4380
3011
  if (!actions) {
4381
3012
  throw new Error("useSlotsActions must be used within a SlotsProvider");
4382
3013
  }