@almadar/ui 5.61.0 → 5.62.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.
Files changed (41) hide show
  1. package/dist/avl/index.cjs +3127 -1681
  2. package/dist/avl/index.js +1948 -502
  3. package/dist/components/core/molecules/GraphCanvas.d.ts +4 -0
  4. package/dist/components/core/templates/index.d.ts +4 -0
  5. package/dist/components/game/molecules/CardHand.d.ts +35 -0
  6. package/dist/components/game/molecules/DialogueBox.d.ts +8 -2
  7. package/dist/components/game/molecules/index.d.ts +1 -0
  8. package/dist/components/game/molecules/three/index.cjs +219 -115
  9. package/dist/components/game/molecules/three/index.js +219 -115
  10. package/dist/components/game/organisms/CardBattlerBoard.d.ts +46 -0
  11. package/dist/components/game/organisms/CityBuilderBoard.d.ts +63 -0
  12. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +64 -0
  13. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +10 -1
  14. package/dist/components/game/organisms/TraitSlot.d.ts +1 -3
  15. package/dist/components/game/organisms/VisualNovelBoard.d.ts +53 -0
  16. package/dist/components/game/organisms/index.d.ts +4 -0
  17. package/dist/components/game/templates/CardBattlerTemplate.d.ts +35 -0
  18. package/dist/components/game/templates/CityBuilderTemplate.d.ts +40 -0
  19. package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +5 -2
  20. package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +5 -2
  21. package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +5 -2
  22. package/dist/components/game/templates/TopDownShooterTemplate.d.ts +42 -0
  23. package/dist/components/game/templates/VisualNovelTemplate.d.ts +28 -0
  24. package/dist/components/game/templates/game3dAssetManifest.d.ts +50 -0
  25. package/dist/components/game/templates/index.d.ts +4 -0
  26. package/dist/components/index.cjs +2993 -1529
  27. package/dist/components/index.js +1961 -506
  28. package/dist/docs/index.cjs +105 -1
  29. package/dist/docs/index.js +105 -1
  30. package/dist/hooks/index.cjs +105 -1
  31. package/dist/hooks/index.js +105 -1
  32. package/dist/locales/index.cjs +315 -3
  33. package/dist/locales/index.js +315 -3
  34. package/dist/providers/index.cjs +2936 -1490
  35. package/dist/providers/index.js +1924 -478
  36. package/dist/runtime/index.cjs +2992 -1546
  37. package/dist/runtime/index.js +1928 -482
  38. package/locales/ar.json +105 -1
  39. package/locales/en.json +105 -1
  40. package/locales/sl.json +105 -1
  41. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import * as React76 from 'react';
3
- import React76__default, { useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, createContext, useLayoutEffect, useId, forwardRef, useImperativeHandle, useSyncExternalStore, Component } from 'react';
2
+ import * as React79 from 'react';
3
+ import React79__default, { useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, createContext, useLayoutEffect, useId, forwardRef, useImperativeHandle, useSyncExternalStore, Component } from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
@@ -233,7 +233,7 @@ var init_SvgFlow = __esm({
233
233
  width = 100,
234
234
  height = 100
235
235
  }) => {
236
- const markerId = React76__default.useMemo(() => {
236
+ const markerId = React79__default.useMemo(() => {
237
237
  flowIdCounter += 1;
238
238
  return `almadar-flow-arrow-${flowIdCounter}`;
239
239
  }, []);
@@ -826,7 +826,7 @@ var init_SvgRing = __esm({
826
826
  width = 100,
827
827
  height = 100
828
828
  }) => {
829
- const gradientId = React76__default.useMemo(() => {
829
+ const gradientId = React79__default.useMemo(() => {
830
830
  ringIdCounter += 1;
831
831
  return `almadar-ring-glow-${ringIdCounter}`;
832
832
  }, []);
@@ -1238,7 +1238,7 @@ function loadLib(key, importer) {
1238
1238
  return p2;
1239
1239
  }
1240
1240
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
1241
- const Lazy = React76__default.lazy(async () => {
1241
+ const Lazy = React79__default.lazy(async () => {
1242
1242
  const lib = await loadLib(libKey, importer);
1243
1243
  const Comp = pick(lib);
1244
1244
  if (!Comp) {
@@ -1248,7 +1248,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
1248
1248
  return { default: Comp };
1249
1249
  });
1250
1250
  const Wrapped = (props) => /* @__PURE__ */ jsx(
1251
- React76__default.Suspense,
1251
+ React79__default.Suspense,
1252
1252
  {
1253
1253
  fallback: /* @__PURE__ */ jsx(
1254
1254
  "span",
@@ -1974,7 +1974,7 @@ var init_Icon = __esm({
1974
1974
  const directIcon = typeof icon === "string" ? void 0 : icon;
1975
1975
  const effectiveName = typeof icon === "string" ? icon : name;
1976
1976
  const family = useIconFamily();
1977
- const RenderedComponent = React76__default.useMemo(() => {
1977
+ const RenderedComponent = React79__default.useMemo(() => {
1978
1978
  if (directIcon) return null;
1979
1979
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
1980
1980
  }, [directIcon, effectiveName, family]);
@@ -2033,7 +2033,7 @@ function resolveIconProp(value, sizeClass) {
2033
2033
  const IconComp = value;
2034
2034
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
2035
2035
  }
2036
- if (React76__default.isValidElement(value)) {
2036
+ if (React79__default.isValidElement(value)) {
2037
2037
  return value;
2038
2038
  }
2039
2039
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -2109,7 +2109,7 @@ var init_Button = __esm({
2109
2109
  md: "h-icon-default w-icon-default",
2110
2110
  lg: "h-icon-default w-icon-default"
2111
2111
  };
2112
- Button = React76__default.forwardRef(
2112
+ Button = React79__default.forwardRef(
2113
2113
  ({
2114
2114
  className,
2115
2115
  variant = "primary",
@@ -2176,7 +2176,7 @@ var init_Input = __esm({
2176
2176
  init_cn();
2177
2177
  init_Icon();
2178
2178
  init_useEventBus();
2179
- Input = React76__default.forwardRef(
2179
+ Input = React79__default.forwardRef(
2180
2180
  ({
2181
2181
  className,
2182
2182
  inputType,
@@ -2336,7 +2336,7 @@ var Label;
2336
2336
  var init_Label = __esm({
2337
2337
  "components/core/atoms/Label.tsx"() {
2338
2338
  init_cn();
2339
- Label = React76__default.forwardRef(
2339
+ Label = React79__default.forwardRef(
2340
2340
  ({ className, required, children, ...props }, ref) => {
2341
2341
  return /* @__PURE__ */ jsxs(
2342
2342
  "label",
@@ -2363,7 +2363,7 @@ var init_Textarea = __esm({
2363
2363
  "components/core/atoms/Textarea.tsx"() {
2364
2364
  init_cn();
2365
2365
  init_useEventBus();
2366
- Textarea = React76__default.forwardRef(
2366
+ Textarea = React79__default.forwardRef(
2367
2367
  ({ className, error, onChange, ...props }, ref) => {
2368
2368
  const eventBus = useEventBus();
2369
2369
  const handleChange = (e) => {
@@ -2602,7 +2602,7 @@ var init_Select = __esm({
2602
2602
  init_cn();
2603
2603
  init_Icon();
2604
2604
  init_useEventBus();
2605
- Select = React76__default.forwardRef(
2605
+ Select = React79__default.forwardRef(
2606
2606
  (props, _ref) => {
2607
2607
  const { multiple, searchable, clearable } = props;
2608
2608
  if (multiple || searchable || clearable) {
@@ -2619,7 +2619,7 @@ var init_Checkbox = __esm({
2619
2619
  "components/core/atoms/Checkbox.tsx"() {
2620
2620
  init_cn();
2621
2621
  init_useEventBus();
2622
- Checkbox = React76__default.forwardRef(
2622
+ Checkbox = React79__default.forwardRef(
2623
2623
  ({ className, label, id, onChange, ...props }, ref) => {
2624
2624
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
2625
2625
  const eventBus = useEventBus();
@@ -2673,7 +2673,7 @@ var init_Spinner = __esm({
2673
2673
  md: "h-6 w-6",
2674
2674
  lg: "h-8 w-8"
2675
2675
  };
2676
- Spinner = React76__default.forwardRef(
2676
+ Spinner = React79__default.forwardRef(
2677
2677
  ({ className, size = "md", overlay, ...props }, ref) => {
2678
2678
  if (overlay) {
2679
2679
  return /* @__PURE__ */ jsx(
@@ -2763,7 +2763,7 @@ var init_Card = __esm({
2763
2763
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
2764
2764
  "tile-image-first": "p-0 overflow-hidden"
2765
2765
  };
2766
- Card = React76__default.forwardRef(
2766
+ Card = React79__default.forwardRef(
2767
2767
  ({
2768
2768
  className,
2769
2769
  variant = "bordered",
@@ -2811,9 +2811,9 @@ var init_Card = __esm({
2811
2811
  }
2812
2812
  );
2813
2813
  Card.displayName = "Card";
2814
- CardHeader = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
2814
+ CardHeader = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
2815
2815
  CardHeader.displayName = "CardHeader";
2816
- CardTitle = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2816
+ CardTitle = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2817
2817
  "h3",
2818
2818
  {
2819
2819
  ref,
@@ -2826,11 +2826,11 @@ var init_Card = __esm({
2826
2826
  }
2827
2827
  ));
2828
2828
  CardTitle.displayName = "CardTitle";
2829
- CardContent = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
2829
+ CardContent = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
2830
2830
  CardContent.displayName = "CardContent";
2831
2831
  CardBody = CardContent;
2832
2832
  CardBody.displayName = "CardBody";
2833
- CardFooter = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2833
+ CardFooter = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2834
2834
  "div",
2835
2835
  {
2836
2836
  ref,
@@ -2883,7 +2883,7 @@ var init_Badge = __esm({
2883
2883
  md: "px-2.5 py-1 text-sm",
2884
2884
  lg: "px-3 py-1.5 text-base"
2885
2885
  };
2886
- Badge = React76__default.forwardRef(
2886
+ Badge = React79__default.forwardRef(
2887
2887
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
2888
2888
  const iconSizes3 = {
2889
2889
  sm: "h-icon-default w-icon-default",
@@ -2976,7 +2976,7 @@ var init_FilterPill = __esm({
2976
2976
  md: "w-3.5 h-3.5",
2977
2977
  lg: "w-4 h-4"
2978
2978
  };
2979
- FilterPill = React76__default.forwardRef(
2979
+ FilterPill = React79__default.forwardRef(
2980
2980
  ({
2981
2981
  className,
2982
2982
  variant = "default",
@@ -3105,8 +3105,8 @@ var init_Avatar = __esm({
3105
3105
  actionPayload
3106
3106
  }) => {
3107
3107
  const eventBus = useEventBus();
3108
- const [imgFailed, setImgFailed] = React76__default.useState(false);
3109
- React76__default.useEffect(() => {
3108
+ const [imgFailed, setImgFailed] = React79__default.useState(false);
3109
+ React79__default.useEffect(() => {
3110
3110
  setImgFailed(false);
3111
3111
  }, [src]);
3112
3112
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -3310,7 +3310,7 @@ var init_Box = __esm({
3310
3310
  fixed: "fixed",
3311
3311
  sticky: "sticky"
3312
3312
  };
3313
- Box = React76__default.forwardRef(
3313
+ Box = React79__default.forwardRef(
3314
3314
  ({
3315
3315
  padding,
3316
3316
  paddingX,
@@ -3360,7 +3360,7 @@ var init_Box = __esm({
3360
3360
  onMouseLeave?.(e);
3361
3361
  }, [hoverEvent, eventBus, onMouseLeave]);
3362
3362
  const isClickable = action || onClick;
3363
- return React76__default.createElement(
3363
+ return React79__default.createElement(
3364
3364
  Component2,
3365
3365
  {
3366
3366
  ref,
@@ -3685,7 +3685,7 @@ var init_Radio = __esm({
3685
3685
  md: "w-2.5 h-2.5",
3686
3686
  lg: "w-3 h-3"
3687
3687
  };
3688
- Radio = React76__default.forwardRef(
3688
+ Radio = React79__default.forwardRef(
3689
3689
  ({
3690
3690
  label,
3691
3691
  helperText,
@@ -3702,12 +3702,12 @@ var init_Radio = __esm({
3702
3702
  onChange,
3703
3703
  ...props
3704
3704
  }, ref) => {
3705
- const reactId = React76__default.useId();
3705
+ const reactId = React79__default.useId();
3706
3706
  const baseId = id || `radio-${reactId}`;
3707
3707
  const hasError = !!error;
3708
3708
  const eventBus = useEventBus();
3709
- const [selected, setSelected] = React76__default.useState(value);
3710
- React76__default.useEffect(() => {
3709
+ const [selected, setSelected] = React79__default.useState(value);
3710
+ React79__default.useEffect(() => {
3711
3711
  if (value !== void 0) setSelected(value);
3712
3712
  }, [value]);
3713
3713
  const pick = (next, e) => {
@@ -3889,7 +3889,7 @@ var init_Switch = __esm({
3889
3889
  "components/core/atoms/Switch.tsx"() {
3890
3890
  "use client";
3891
3891
  init_cn();
3892
- Switch = React76.forwardRef(
3892
+ Switch = React79.forwardRef(
3893
3893
  ({
3894
3894
  checked,
3895
3895
  defaultChecked = false,
@@ -3900,10 +3900,10 @@ var init_Switch = __esm({
3900
3900
  name,
3901
3901
  className
3902
3902
  }, ref) => {
3903
- const [isChecked, setIsChecked] = React76.useState(
3903
+ const [isChecked, setIsChecked] = React79.useState(
3904
3904
  checked !== void 0 ? checked : defaultChecked
3905
3905
  );
3906
- React76.useEffect(() => {
3906
+ React79.useEffect(() => {
3907
3907
  if (checked !== void 0) {
3908
3908
  setIsChecked(checked);
3909
3909
  }
@@ -4555,7 +4555,7 @@ var Dialog;
4555
4555
  var init_Dialog = __esm({
4556
4556
  "components/core/atoms/Dialog.tsx"() {
4557
4557
  init_cn();
4558
- Dialog = React76__default.forwardRef(
4558
+ Dialog = React79__default.forwardRef(
4559
4559
  ({
4560
4560
  role = "dialog",
4561
4561
  "aria-modal": ariaModal = true,
@@ -4581,7 +4581,7 @@ var Aside;
4581
4581
  var init_Aside = __esm({
4582
4582
  "components/core/atoms/Aside.tsx"() {
4583
4583
  init_cn();
4584
- Aside = React76__default.forwardRef(
4584
+ Aside = React79__default.forwardRef(
4585
4585
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
4586
4586
  );
4587
4587
  Aside.displayName = "Aside";
@@ -4659,8 +4659,8 @@ var init_LawReferenceTooltip = __esm({
4659
4659
  className
4660
4660
  }) => {
4661
4661
  const { t } = useTranslate();
4662
- const [isVisible, setIsVisible] = React76__default.useState(false);
4663
- const timeoutRef = React76__default.useRef(null);
4662
+ const [isVisible, setIsVisible] = React79__default.useState(false);
4663
+ const timeoutRef = React79__default.useRef(null);
4664
4664
  const handleMouseEnter = () => {
4665
4665
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4666
4666
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -4669,7 +4669,7 @@ var init_LawReferenceTooltip = __esm({
4669
4669
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4670
4670
  setIsVisible(false);
4671
4671
  };
4672
- React76__default.useEffect(() => {
4672
+ React79__default.useEffect(() => {
4673
4673
  return () => {
4674
4674
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4675
4675
  };
@@ -4879,7 +4879,7 @@ var init_StatusDot = __esm({
4879
4879
  md: "w-2.5 h-2.5",
4880
4880
  lg: "w-3 h-3"
4881
4881
  };
4882
- StatusDot = React76__default.forwardRef(
4882
+ StatusDot = React79__default.forwardRef(
4883
4883
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
4884
4884
  return /* @__PURE__ */ jsx(
4885
4885
  "span",
@@ -4933,7 +4933,7 @@ var init_TrendIndicator = __esm({
4933
4933
  down: "trending-down",
4934
4934
  flat: "arrow-right"
4935
4935
  };
4936
- TrendIndicator = React76__default.forwardRef(
4936
+ TrendIndicator = React79__default.forwardRef(
4937
4937
  ({
4938
4938
  className,
4939
4939
  value,
@@ -5000,7 +5000,7 @@ var init_RangeSlider = __esm({
5000
5000
  md: "w-4 h-4",
5001
5001
  lg: "w-5 h-5"
5002
5002
  };
5003
- RangeSlider = React76__default.forwardRef(
5003
+ RangeSlider = React79__default.forwardRef(
5004
5004
  ({
5005
5005
  className,
5006
5006
  min = 0,
@@ -5596,7 +5596,7 @@ var init_ContentSection = __esm({
5596
5596
  md: "py-16",
5597
5597
  lg: "py-24"
5598
5598
  };
5599
- ContentSection = React76__default.forwardRef(
5599
+ ContentSection = React79__default.forwardRef(
5600
5600
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
5601
5601
  return /* @__PURE__ */ jsx(
5602
5602
  Box,
@@ -6130,7 +6130,7 @@ var init_AnimatedReveal = __esm({
6130
6130
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6131
6131
  "none": {}
6132
6132
  };
6133
- AnimatedReveal = React76__default.forwardRef(
6133
+ AnimatedReveal = React79__default.forwardRef(
6134
6134
  ({
6135
6135
  trigger = "scroll",
6136
6136
  animation = "fade-up",
@@ -6290,7 +6290,7 @@ var init_AnimatedGraphic = __esm({
6290
6290
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
6291
6291
  "use client";
6292
6292
  init_cn();
6293
- AnimatedGraphic = React76__default.forwardRef(
6293
+ AnimatedGraphic = React79__default.forwardRef(
6294
6294
  ({
6295
6295
  src,
6296
6296
  svgContent,
@@ -6313,7 +6313,7 @@ var init_AnimatedGraphic = __esm({
6313
6313
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6314
6314
  const resolvedSvg = svgContent ?? fetchedSvg;
6315
6315
  const prevAnimateRef = useRef(animate);
6316
- const setRef = React76__default.useCallback(
6316
+ const setRef = React79__default.useCallback(
6317
6317
  (node) => {
6318
6318
  containerRef.current = node;
6319
6319
  if (typeof ref === "function") ref(node);
@@ -6995,7 +6995,7 @@ var init_ErrorBoundary = __esm({
6995
6995
  }
6996
6996
  );
6997
6997
  };
6998
- ErrorBoundary = class extends React76__default.Component {
6998
+ ErrorBoundary = class extends React79__default.Component {
6999
6999
  constructor(props) {
7000
7000
  super(props);
7001
7001
  __publicField(this, "reset", () => {
@@ -8115,9 +8115,9 @@ function ControlButton({
8115
8115
  className
8116
8116
  }) {
8117
8117
  const eventBus = useEventBus();
8118
- const [isPressed, setIsPressed] = React76.useState(false);
8118
+ const [isPressed, setIsPressed] = React79.useState(false);
8119
8119
  const actualPressed = pressed ?? isPressed;
8120
- const handlePointerDown = React76.useCallback(
8120
+ const handlePointerDown = React79.useCallback(
8121
8121
  (e) => {
8122
8122
  e.preventDefault();
8123
8123
  if (disabled) return;
@@ -8127,7 +8127,7 @@ function ControlButton({
8127
8127
  },
8128
8128
  [disabled, pressEvent, eventBus, onPress]
8129
8129
  );
8130
- const handlePointerUp = React76.useCallback(
8130
+ const handlePointerUp = React79.useCallback(
8131
8131
  (e) => {
8132
8132
  e.preventDefault();
8133
8133
  if (disabled) return;
@@ -8137,7 +8137,7 @@ function ControlButton({
8137
8137
  },
8138
8138
  [disabled, releaseEvent, eventBus, onRelease]
8139
8139
  );
8140
- const handlePointerLeave = React76.useCallback(
8140
+ const handlePointerLeave = React79.useCallback(
8141
8141
  (e) => {
8142
8142
  if (isPressed) {
8143
8143
  setIsPressed(false);
@@ -8225,8 +8225,8 @@ function ActionButtons({
8225
8225
  disabled
8226
8226
  }) {
8227
8227
  const eventBus = useEventBus();
8228
- const [activeButtons, setActiveButtons] = React76.useState(/* @__PURE__ */ new Set());
8229
- const handlePress = React76.useCallback(
8228
+ const [activeButtons, setActiveButtons] = React79.useState(/* @__PURE__ */ new Set());
8229
+ const handlePress = React79.useCallback(
8230
8230
  (id) => {
8231
8231
  setActiveButtons((prev) => new Set(prev).add(id));
8232
8232
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -8234,7 +8234,7 @@ function ActionButtons({
8234
8234
  },
8235
8235
  [actionEvent, eventBus, onAction]
8236
8236
  );
8237
- const handleRelease = React76.useCallback(
8237
+ const handleRelease = React79.useCallback(
8238
8238
  (id) => {
8239
8239
  setActiveButtons((prev) => {
8240
8240
  const next = new Set(prev);
@@ -8871,8 +8871,8 @@ var init_AnimatedCounter2 = __esm({
8871
8871
  const [displayValue, setDisplayValue] = useState("0");
8872
8872
  const [hasAnimated, setHasAnimated] = useState(false);
8873
8873
  const animate = useCallback(() => {
8874
- const { num: num2, prefix, suffix, decimals } = parseValue(value);
8875
- if (num2 === 0) {
8874
+ const { num: num3, prefix, suffix, decimals } = parseValue(value);
8875
+ if (num3 === 0) {
8876
8876
  setDisplayValue(String(value));
8877
8877
  return;
8878
8878
  }
@@ -8881,7 +8881,7 @@ var init_AnimatedCounter2 = __esm({
8881
8881
  const elapsed = now - startTime;
8882
8882
  const progress = Math.min(elapsed / duration, 1);
8883
8883
  const eased = 1 - Math.pow(1 - progress, 3);
8884
- const current = eased * num2;
8884
+ const current = eased * num3;
8885
8885
  setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
8886
8886
  if (progress < 1) {
8887
8887
  requestAnimationFrame(tick);
@@ -9737,7 +9737,7 @@ function IsometricCanvas({
9737
9737
  // Tuning
9738
9738
  diamondTopY: diamondTopYProp,
9739
9739
  // Remote asset loading
9740
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
9740
+ assetBaseUrl,
9741
9741
  assetManifest
9742
9742
  }) {
9743
9743
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -9816,7 +9816,7 @@ function IsometricCanvas({
9816
9816
  const attackTargetSet = useMemo(() => {
9817
9817
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
9818
9818
  }, [attackTargets]);
9819
- const resolveManifestUrl = useCallback((relativePath) => {
9819
+ const resolveManifestUrl7 = useCallback((relativePath) => {
9820
9820
  if (!relativePath) return void 0;
9821
9821
  if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
9822
9822
  return relativePath;
@@ -9829,7 +9829,7 @@ function IsometricCanvas({
9829
9829
  const url = getTerrainSprite(tile.terrain ?? "");
9830
9830
  if (url) urls.push(url);
9831
9831
  } else {
9832
- const url = resolveManifestUrl(assetManifest?.terrains?.[tile.terrain ?? ""]);
9832
+ const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
9833
9833
  if (url) urls.push(url);
9834
9834
  }
9835
9835
  }
@@ -9839,7 +9839,7 @@ function IsometricCanvas({
9839
9839
  const url = getFeatureSprite(feature.type);
9840
9840
  if (url) urls.push(url);
9841
9841
  } else {
9842
- const url = resolveManifestUrl(assetManifest?.features?.[feature.type]);
9842
+ const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
9843
9843
  if (url) urls.push(url);
9844
9844
  }
9845
9845
  }
@@ -9849,13 +9849,13 @@ function IsometricCanvas({
9849
9849
  const url = getUnitSprite(unit);
9850
9850
  if (url) urls.push(url);
9851
9851
  } else if (unit.unitType) {
9852
- const url = resolveManifestUrl(assetManifest?.units?.[unit.unitType]);
9852
+ const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
9853
9853
  if (url) urls.push(url);
9854
9854
  }
9855
9855
  }
9856
9856
  if (assetManifest?.effects) {
9857
9857
  for (const path of Object.values(assetManifest.effects)) {
9858
- const url = resolveManifestUrl(path);
9858
+ const url = resolveManifestUrl7(path);
9859
9859
  if (url) urls.push(url);
9860
9860
  }
9861
9861
  }
@@ -9863,7 +9863,7 @@ function IsometricCanvas({
9863
9863
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
9864
9864
  if (backgroundImage) urls.push(backgroundImage);
9865
9865
  return [...new Set(urls.filter(Boolean))];
9866
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
9866
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
9867
9867
  const { getImage, pendingCount } = useImageCache(spriteUrls);
9868
9868
  useEffect(() => {
9869
9869
  if (typeof window === "undefined") return;
@@ -9888,14 +9888,14 @@ function IsometricCanvas({
9888
9888
  lerpToTarget
9889
9889
  } = useCamera();
9890
9890
  const resolveTerrainSpriteUrl = useCallback((tile) => {
9891
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl(assetManifest?.terrains?.[tile.terrain ?? ""]);
9892
- }, [getTerrainSprite, assetManifest, resolveManifestUrl]);
9891
+ return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
9892
+ }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
9893
9893
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
9894
- return getFeatureSprite?.(featureType) || resolveManifestUrl(assetManifest?.features?.[featureType]);
9895
- }, [getFeatureSprite, assetManifest, resolveManifestUrl]);
9894
+ return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
9895
+ }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
9896
9896
  const resolveUnitSpriteUrl = useCallback((unit) => {
9897
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl(assetManifest?.units?.[unit.unitType]) : void 0);
9898
- }, [getUnitSprite, assetManifest, resolveManifestUrl]);
9897
+ return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
9898
+ }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
9899
9899
  const drawMinimap = useCallback(() => {
9900
9900
  if (!showMinimap) return;
9901
9901
  const miniCanvas = minimapRef.current;
@@ -9997,7 +9997,15 @@ function IsometricCanvas({
9997
9997
  const spriteUrl = resolveTerrainSpriteUrl(tile);
9998
9998
  const img = spriteUrl ? getImage(spriteUrl) : null;
9999
9999
  if (img) {
10000
- ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10000
+ if (img.naturalWidth === 0) {
10001
+ ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10002
+ } else {
10003
+ const drawW = scaledTileWidth;
10004
+ const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
10005
+ const drawX = pos.x;
10006
+ const drawY = pos.y + scaledTileHeight - drawH;
10007
+ ctx.drawImage(img, drawX, drawY, drawW, drawH);
10008
+ }
10001
10009
  } else {
10002
10010
  const centerX = pos.x + scaledTileWidth / 2;
10003
10011
  const topY = pos.y + scaledDiamondTopY;
@@ -12256,7 +12264,7 @@ var init_CodeBlock = __esm({
12256
12264
  };
12257
12265
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
12258
12266
  HIDDEN_LINE_NUMBERS = { display: "none" };
12259
- CodeBlock = React76__default.memo(
12267
+ CodeBlock = React79__default.memo(
12260
12268
  ({
12261
12269
  code: rawCode,
12262
12270
  language = "text",
@@ -12425,24 +12433,24 @@ var init_CodeBlock = __esm({
12425
12433
  return;
12426
12434
  }
12427
12435
  lineEls.forEach((el) => {
12428
- const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
12429
- if (hiddenLines.has(num2)) {
12436
+ const num3 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
12437
+ if (hiddenLines.has(num3)) {
12430
12438
  el.style.display = "none";
12431
12439
  return;
12432
12440
  }
12433
12441
  el.style.display = "";
12434
12442
  el.style.position = "relative";
12435
12443
  el.style.paddingLeft = "1.2em";
12436
- const region = foldStartMap.get(num2);
12444
+ const region = foldStartMap.get(num3);
12437
12445
  if (!region) return;
12438
- const isCollapsed = collapsed.has(num2);
12446
+ const isCollapsed = collapsed.has(num3);
12439
12447
  const toggle = document.createElement("span");
12440
12448
  toggle.className = "fold-toggle";
12441
12449
  toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
12442
12450
  toggle.style.cssText = "position:absolute;left:0;top:0;width:1.2em;text-align:center;cursor:pointer;color:#858585;font-size:10px;user-select:none;line-height:inherit;height:100%";
12443
12451
  toggle.addEventListener("click", (e) => {
12444
12452
  e.stopPropagation();
12445
- toggleFoldRef.current(num2);
12453
+ toggleFoldRef.current(num3);
12446
12454
  });
12447
12455
  el.insertBefore(toggle, el.firstChild);
12448
12456
  if (isCollapsed) {
@@ -12843,7 +12851,7 @@ var init_MarkdownContent = __esm({
12843
12851
  init_Box();
12844
12852
  init_CodeBlock();
12845
12853
  init_cn();
12846
- MarkdownContent = React76__default.memo(
12854
+ MarkdownContent = React79__default.memo(
12847
12855
  ({ content, direction = "ltr", className }) => {
12848
12856
  const { t: _t } = useTranslate();
12849
12857
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -14160,7 +14168,7 @@ var init_StateMachineView = __esm({
14160
14168
  style: { top: title ? 30 : 0 },
14161
14169
  children: [
14162
14170
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
14163
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React76__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
14171
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React79__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
14164
14172
  StateNode,
14165
14173
  {
14166
14174
  state,
@@ -18061,8 +18069,8 @@ function EmojiEffect({
18061
18069
  );
18062
18070
  }
18063
18071
  function CanvasEffect({
18064
- effectSpriteUrl = "https://almadar-kflow-assets.web.app/shared/effects/gas/gas00.png",
18065
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/effects/",
18072
+ effectSpriteUrl,
18073
+ assetBaseUrl,
18066
18074
  ...props
18067
18075
  }) {
18068
18076
  const eventBus = useEventBus();
@@ -18105,6 +18113,380 @@ var init_CanvasEffect = __esm({
18105
18113
  CanvasEffect.displayName = "CanvasEffect";
18106
18114
  }
18107
18115
  });
18116
+ function CardHand({
18117
+ cards = DEFAULT_CARDS,
18118
+ selectedId = "",
18119
+ size = "md",
18120
+ onCardClick,
18121
+ cardClickEvent,
18122
+ emptyLabel = "No cards in hand",
18123
+ className
18124
+ }) {
18125
+ const eventBus = useEventBus();
18126
+ const handleClick = React79.useCallback(
18127
+ (card) => {
18128
+ if (card.disabled) return;
18129
+ onCardClick?.(card.id);
18130
+ if (cardClickEvent) {
18131
+ eventBus.emit(`UI:${cardClickEvent}`, { cardId: card.id });
18132
+ }
18133
+ },
18134
+ [onCardClick, cardClickEvent, eventBus]
18135
+ );
18136
+ if (cards.length === 0) {
18137
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center p-4", className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: emptyLabel }) });
18138
+ }
18139
+ const art = artSizeMap[size];
18140
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex flex-wrap gap-2 justify-center items-end", className), children: cards.map((card) => {
18141
+ const selected = selectedId === card.id;
18142
+ return /* @__PURE__ */ jsxs(
18143
+ "button",
18144
+ {
18145
+ type: "button",
18146
+ onClick: () => handleClick(card),
18147
+ disabled: card.disabled,
18148
+ title: card.title,
18149
+ className: cn(
18150
+ "card-hand-card relative flex flex-col items-center rounded-interactive border-2",
18151
+ "bg-card/90 px-1.5 pt-1.5 pb-1 transition-all duration-150",
18152
+ cardSizeMap[size],
18153
+ card.disabled ? "border-border opacity-50 cursor-not-allowed" : "border-accent hover:brightness-125 hover:-translate-y-1 cursor-pointer",
18154
+ selected && "ring-2 ring-foreground ring-offset-1 ring-offset-background -translate-y-1"
18155
+ ),
18156
+ children: [
18157
+ card.cost != null && /* @__PURE__ */ jsx(
18158
+ "span",
18159
+ {
18160
+ className: cn(
18161
+ "absolute -top-2 -left-2 flex items-center justify-center",
18162
+ "min-w-[22px] h-[22px] rounded-full px-1",
18163
+ "bg-info text-foreground text-xs font-bold border border-background"
18164
+ ),
18165
+ children: card.cost
18166
+ }
18167
+ ),
18168
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
18169
+ "img",
18170
+ {
18171
+ src: card.iconUrl,
18172
+ alt: card.title ?? card.id,
18173
+ width: art,
18174
+ height: art,
18175
+ style: { imageRendering: "pixelated", objectFit: "contain" },
18176
+ className: "flex-shrink-0"
18177
+ }
18178
+ ) : /* @__PURE__ */ jsx(
18179
+ Box,
18180
+ {
18181
+ className: "rounded bg-muted/40",
18182
+ style: { width: art, height: art }
18183
+ }
18184
+ ) }),
18185
+ card.title != null && /* @__PURE__ */ jsx(
18186
+ Typography,
18187
+ {
18188
+ variant: "small",
18189
+ className: "w-full truncate text-center text-[10px] leading-tight font-semibold",
18190
+ children: card.title
18191
+ }
18192
+ ),
18193
+ (card.attack != null || card.defense != null) && /* @__PURE__ */ jsxs(Box, { className: "flex w-full items-center justify-between px-0.5 text-[10px] font-bold leading-none", children: [
18194
+ /* @__PURE__ */ jsx("span", { className: "text-error", children: card.attack != null ? `\u2694${card.attack}` : "" }),
18195
+ /* @__PURE__ */ jsx("span", { className: "text-info", children: card.defense != null ? `\u{1F6E1}${card.defense}` : "" })
18196
+ ] })
18197
+ ]
18198
+ },
18199
+ card.id
18200
+ );
18201
+ }) });
18202
+ }
18203
+ var cardSizeMap, artSizeMap, DEFAULT_CARDS;
18204
+ var init_CardHand = __esm({
18205
+ "components/game/molecules/CardHand.tsx"() {
18206
+ "use client";
18207
+ init_cn();
18208
+ init_useEventBus();
18209
+ init_Box();
18210
+ init_Typography();
18211
+ cardSizeMap = {
18212
+ sm: "w-16 h-24",
18213
+ md: "w-20 h-28",
18214
+ lg: "w-24 h-36"
18215
+ };
18216
+ artSizeMap = {
18217
+ sm: 40,
18218
+ md: 52,
18219
+ lg: 64
18220
+ };
18221
+ DEFAULT_CARDS = [
18222
+ { id: "card-1", title: "Brawler", cost: 1, attack: 2, defense: 1 },
18223
+ { id: "card-2", title: "Guardian", cost: 2, attack: 1, defense: 4 },
18224
+ { id: "card-3", title: "Striker", cost: 3, attack: 5, defense: 2 }
18225
+ ];
18226
+ CardHand.displayName = "CardHand";
18227
+ }
18228
+ });
18229
+ function resolveManifestUrl(manifest, relative) {
18230
+ if (relative == null) return void 0;
18231
+ if (/^https?:\/\//.test(relative)) return relative;
18232
+ const base = manifest?.baseUrl;
18233
+ if (base == null) return relative;
18234
+ const cleanBase = base.replace(/\/$/, "");
18235
+ const cleanRel = relative.replace(/^\//, "");
18236
+ return `${cleanBase}/${cleanRel}`;
18237
+ }
18238
+ function rowToCard(r) {
18239
+ return {
18240
+ id: str(r.id),
18241
+ iconKey: r.iconKey == null ? void 0 : str(r.iconKey),
18242
+ title: r.title == null ? void 0 : str(r.title),
18243
+ cost: r.cost == null ? void 0 : num(r.cost),
18244
+ attack: r.attack == null ? void 0 : num(r.attack),
18245
+ defense: r.defense == null ? void 0 : num(r.defense)
18246
+ };
18247
+ }
18248
+ function toHandCards(cards, manifest, mana) {
18249
+ return cards.map((c) => {
18250
+ const key = c.iconKey ?? c.id;
18251
+ const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
18252
+ return {
18253
+ id: c.id,
18254
+ iconUrl,
18255
+ title: c.title,
18256
+ cost: c.cost,
18257
+ attack: c.attack,
18258
+ defense: c.defense,
18259
+ disabled: c.cost != null && c.cost > mana
18260
+ };
18261
+ });
18262
+ }
18263
+ function CardBattlerBoard({
18264
+ entity,
18265
+ deck: propDeck,
18266
+ hand: propHand,
18267
+ board: propBoard,
18268
+ mana: propMana,
18269
+ maxMana: propMaxMana,
18270
+ turn: propTurn,
18271
+ result: propResult,
18272
+ assetManifest: propAssetManifest,
18273
+ playCardEvent,
18274
+ endTurnEvent,
18275
+ playAgainEvent,
18276
+ gameEndEvent,
18277
+ className
18278
+ }) {
18279
+ const board = boardEntity(entity) ?? {};
18280
+ const eventBus = useEventBus();
18281
+ const { t } = useTranslate();
18282
+ const assetManifest = propAssetManifest ?? board.assetManifest;
18283
+ const entityHand = useMemo(() => rows(board.hand).map(rowToCard), [board.hand]);
18284
+ const rawHand = propHand ?? entityHand;
18285
+ const hand = rawHand.length > 0 ? rawHand : DEFAULT_HAND;
18286
+ const entityBoard = useMemo(() => rows(board.board).map(rowToCard), [board.board]);
18287
+ const playedCards = propBoard ?? entityBoard;
18288
+ const entityDeck = useMemo(() => rows(board.deck).map(rowToCard), [board.deck]);
18289
+ const deck = propDeck ?? entityDeck;
18290
+ const mana = propMana ?? num(board.mana, 3);
18291
+ const maxMana = propMaxMana ?? num(board.maxMana, 3);
18292
+ const turn = propTurn ?? num(board.turn, 1);
18293
+ const result = propResult ?? (str(board.result) || "none");
18294
+ const handCards = useMemo(() => toHandCards(hand, assetManifest, mana), [hand, assetManifest, mana]);
18295
+ const boardCards = useMemo(() => toHandCards(playedCards, assetManifest, mana), [playedCards, assetManifest, mana]);
18296
+ const emittedGameEnd = useRef(false);
18297
+ if (result !== "none" && !emittedGameEnd.current) {
18298
+ emittedGameEnd.current = true;
18299
+ if (gameEndEvent) {
18300
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
18301
+ }
18302
+ }
18303
+ if (result === "none") {
18304
+ emittedGameEnd.current = false;
18305
+ }
18306
+ const handlePlayCard = useCallback((cardId) => {
18307
+ if (result !== "none") return;
18308
+ if (playCardEvent) {
18309
+ eventBus.emit(`UI:${playCardEvent}`, { cardId });
18310
+ }
18311
+ }, [result, playCardEvent, eventBus]);
18312
+ const handleEndTurn = useCallback(() => {
18313
+ if (result !== "none") return;
18314
+ if (endTurnEvent) {
18315
+ eventBus.emit(`UI:${endTurnEvent}`, {});
18316
+ }
18317
+ }, [result, endTurnEvent, eventBus]);
18318
+ const handlePlayAgain = useCallback(() => {
18319
+ if (playAgainEvent) {
18320
+ eventBus.emit(`UI:${playAgainEvent}`, {});
18321
+ }
18322
+ }, [playAgainEvent, eventBus]);
18323
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("card-battler-board relative min-h-[600px] bg-background", className), gap: "none", children: [
18324
+ /* @__PURE__ */ jsxs(
18325
+ HStack,
18326
+ {
18327
+ className: "px-4 py-2 border-b border-border bg-surface",
18328
+ gap: "lg",
18329
+ align: "center",
18330
+ children: [
18331
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
18332
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.mana") ?? "Mana" }),
18333
+ /* @__PURE__ */ jsxs(Typography, { variant: "body2", weight: "bold", className: "text-info", children: [
18334
+ mana,
18335
+ " / ",
18336
+ maxMana
18337
+ ] })
18338
+ ] }),
18339
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
18340
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.turn") ?? "Turn" }),
18341
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: turn })
18342
+ ] }),
18343
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
18344
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.deck") ?? "Deck" }),
18345
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: deck.length })
18346
+ ] }),
18347
+ /* @__PURE__ */ jsx(Box, { className: "ml-auto", children: result === "none" && /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleEndTurn, children: t("cb.endTurn") ?? "End Turn" }) })
18348
+ ]
18349
+ }
18350
+ ),
18351
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 relative p-4 overflow-auto", children: [
18352
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", className: "mb-2 uppercase tracking-wide", children: t("cb.battlefield") ?? "Battlefield" }),
18353
+ boardCards.length > 0 ? /* @__PURE__ */ jsx(
18354
+ CardHand,
18355
+ {
18356
+ cards: boardCards,
18357
+ size: "md",
18358
+ className: "justify-start"
18359
+ }
18360
+ ) : /* @__PURE__ */ jsx(Box, { className: "flex items-center justify-center h-32 rounded-interactive border-2 border-dashed border-border", children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.emptyBoard") ?? "Play a card to begin" }) })
18361
+ ] }),
18362
+ /* @__PURE__ */ jsxs(Box, { className: "border-t border-border bg-surface px-4 py-3", children: [
18363
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", className: "mb-2 uppercase tracking-wide", children: t("cb.hand") ?? "Your Hand" }),
18364
+ /* @__PURE__ */ jsx(
18365
+ CardHand,
18366
+ {
18367
+ cards: handCards,
18368
+ size: "lg",
18369
+ onCardClick: handlePlayCard,
18370
+ emptyLabel: t("cb.emptyHand") ?? "No cards in hand"
18371
+ }
18372
+ )
18373
+ ] }),
18374
+ result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
18375
+ /* @__PURE__ */ jsx(
18376
+ Typography,
18377
+ {
18378
+ variant: "h2",
18379
+ className: cn(
18380
+ "text-4xl font-black tracking-widest uppercase",
18381
+ result === "won" ? "text-warning" : "text-error"
18382
+ ),
18383
+ children: result === "won" ? t("cb.victory") ?? "Victory!" : t("cb.defeat") ?? "Defeat!"
18384
+ }
18385
+ ),
18386
+ /* @__PURE__ */ jsx(
18387
+ Button,
18388
+ {
18389
+ variant: "primary",
18390
+ className: "px-8 py-3 font-semibold",
18391
+ onClick: handlePlayAgain,
18392
+ children: t("cb.playAgain") ?? "Play Again"
18393
+ }
18394
+ )
18395
+ ] }) })
18396
+ ] });
18397
+ }
18398
+ var DEFAULT_HAND;
18399
+ var init_CardBattlerBoard = __esm({
18400
+ "components/game/organisms/CardBattlerBoard.tsx"() {
18401
+ "use client";
18402
+ init_cn();
18403
+ init_useEventBus();
18404
+ init_Box();
18405
+ init_Button();
18406
+ init_Typography();
18407
+ init_Stack();
18408
+ init_CardHand();
18409
+ init_boardEntity();
18410
+ DEFAULT_HAND = [
18411
+ { id: "c1", iconKey: "bear", title: "Bear", cost: 3, attack: 5, defense: 4 },
18412
+ { id: "c2", iconKey: "owl", title: "Owl", cost: 1, attack: 2, defense: 1 },
18413
+ { id: "c3", iconKey: "gorilla", title: "Gorilla", cost: 4, attack: 6, defense: 5 },
18414
+ { id: "c4", iconKey: "frog", title: "Frog", cost: 1, attack: 1, defense: 2 },
18415
+ { id: "c5", iconKey: "snake", title: "Snake", cost: 2, attack: 4, defense: 1 }
18416
+ ];
18417
+ CardBattlerBoard.displayName = "CardBattlerBoard";
18418
+ }
18419
+ });
18420
+ function isEntityRow(value) {
18421
+ return value != null && typeof value === "object" && !Array.isArray(value);
18422
+ }
18423
+ function CardBattlerTemplate({
18424
+ entity,
18425
+ title = "Card Battler",
18426
+ deck,
18427
+ hand,
18428
+ board,
18429
+ mana,
18430
+ maxMana,
18431
+ turn,
18432
+ result,
18433
+ assetManifest,
18434
+ playCardEvent,
18435
+ endTurnEvent,
18436
+ playAgainEvent,
18437
+ gameEndEvent,
18438
+ className
18439
+ }) {
18440
+ const resolved = isEntityRow(entity) ? entity : void 0;
18441
+ return /* @__PURE__ */ jsxs(
18442
+ Box,
18443
+ {
18444
+ display: "flex",
18445
+ fullHeight: true,
18446
+ className: cn("card-battler-template flex-col", className),
18447
+ children: [
18448
+ /* @__PURE__ */ jsx(
18449
+ HStack,
18450
+ {
18451
+ gap: "sm",
18452
+ align: "center",
18453
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
18454
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
18455
+ }
18456
+ ),
18457
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
18458
+ CardBattlerBoard,
18459
+ {
18460
+ entity: resolved,
18461
+ deck,
18462
+ hand,
18463
+ board,
18464
+ mana,
18465
+ maxMana,
18466
+ turn,
18467
+ result,
18468
+ assetManifest,
18469
+ playCardEvent,
18470
+ endTurnEvent,
18471
+ playAgainEvent,
18472
+ gameEndEvent,
18473
+ className: "h-full"
18474
+ }
18475
+ ) })
18476
+ ]
18477
+ }
18478
+ );
18479
+ }
18480
+ var init_CardBattlerTemplate = __esm({
18481
+ "components/game/templates/CardBattlerTemplate.tsx"() {
18482
+ init_cn();
18483
+ init_Box();
18484
+ init_Stack();
18485
+ init_Typography();
18486
+ init_CardBattlerBoard();
18487
+ CardBattlerTemplate.displayName = "CardBattlerTemplate";
18488
+ }
18489
+ });
18108
18490
 
18109
18491
  // lib/getNestedValue.ts
18110
18492
  function getNestedValue(obj, path) {
@@ -19933,6 +20315,315 @@ var init_ChoiceButton = __esm({
19933
20315
  ChoiceButton.displayName = "ChoiceButton";
19934
20316
  }
19935
20317
  });
20318
+ function resolveManifestUrl2(manifest, relative) {
20319
+ if (relative == null) return void 0;
20320
+ if (/^https?:\/\//.test(relative)) return relative;
20321
+ const base = manifest?.baseUrl;
20322
+ if (base == null) return relative;
20323
+ const cleanBase = base.replace(/\/$/, "");
20324
+ const cleanRel = relative.replace(/^\//, "");
20325
+ return `${cleanBase}/${cleanRel}`;
20326
+ }
20327
+ function buildDefaultCBTiles() {
20328
+ const tiles = [];
20329
+ for (let y = 0; y < CB_GRID_H; y++) {
20330
+ for (let x = 0; x < CB_GRID_W; x++) {
20331
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
20332
+ const terrainKey = ["grass", "stone", "dirt"][variant];
20333
+ tiles.push({ x, y, terrain: terrainKey, passable: true });
20334
+ }
20335
+ }
20336
+ return tiles;
20337
+ }
20338
+ function tilesToIso(tiles, manifest) {
20339
+ return tiles.map((t) => {
20340
+ const key = t.terrain ?? "grass";
20341
+ const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
20342
+ return {
20343
+ x: t.x,
20344
+ y: t.y,
20345
+ terrain: t.terrain,
20346
+ terrainSprite: sprite,
20347
+ passable: t.passable
20348
+ };
20349
+ });
20350
+ }
20351
+ function buildingsToFeatures(buildings, manifest) {
20352
+ return buildings.map((b) => ({
20353
+ id: b.id,
20354
+ x: b.x,
20355
+ y: b.y,
20356
+ type: b.type,
20357
+ sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
20358
+ }));
20359
+ }
20360
+ function CityBuilderBoard({
20361
+ entity,
20362
+ tiles: propTiles,
20363
+ buildings: propBuildings,
20364
+ assetManifest: propAssetManifest,
20365
+ buildTypes: propBuildTypes,
20366
+ pendingBuildType: propPendingBuildType,
20367
+ gold: propGold,
20368
+ wood: propWood,
20369
+ population: propPopulation,
20370
+ result: propResult,
20371
+ scale = 0.3,
20372
+ unitScale = 0.6,
20373
+ spriteHeightRatio = 1.5,
20374
+ spriteMaxWidthRatio = 0.7,
20375
+ selectBuildTypeEvent,
20376
+ placeBuildingEvent,
20377
+ gameEndEvent,
20378
+ className
20379
+ }) {
20380
+ const board = boardEntity(entity) ?? {};
20381
+ const eventBus = useEventBus();
20382
+ const { t } = useTranslate();
20383
+ const assetManifest = propAssetManifest ?? board.assetManifest;
20384
+ const entityTiles = useMemo(
20385
+ () => rows(board.tiles).map((r) => ({
20386
+ x: num(r.x),
20387
+ y: num(r.y),
20388
+ terrain: r.terrain == null ? void 0 : str(r.terrain),
20389
+ terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
20390
+ passable: r.passable !== false
20391
+ })),
20392
+ [board.tiles]
20393
+ );
20394
+ const rawTiles = propTiles ?? entityTiles;
20395
+ const tiles = rawTiles.length >= CB_GRID_W * CB_GRID_H ? rawTiles : DEFAULT_CB_TILES;
20396
+ const entityBuildings = useMemo(
20397
+ () => rows(board.buildings).map((r) => ({
20398
+ id: str(r.id),
20399
+ x: num(r.x),
20400
+ y: num(r.y),
20401
+ type: str(r.type)
20402
+ })),
20403
+ [board.buildings]
20404
+ );
20405
+ const buildings = propBuildings ?? entityBuildings;
20406
+ const buildTypes = propBuildTypes ?? DEFAULT_BUILD_TYPES;
20407
+ const gold = propGold ?? num(board.gold, 100);
20408
+ const wood = propWood ?? num(board.wood, 80);
20409
+ const population = propPopulation ?? num(board.population, 0);
20410
+ const pendingBuildType = propPendingBuildType ?? (str(board.pendingBuildType) || buildTypes[0]?.type || "");
20411
+ const result = propResult ?? (str(board.result) || "none");
20412
+ const [hoveredTile, setHoveredTile] = useState(null);
20413
+ const emittedGameEnd = useRef(false);
20414
+ if (result !== "none" && !emittedGameEnd.current) {
20415
+ emittedGameEnd.current = true;
20416
+ if (gameEndEvent) {
20417
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
20418
+ }
20419
+ }
20420
+ if (result === "none") {
20421
+ emittedGameEnd.current = false;
20422
+ }
20423
+ const pendingCost = useMemo(
20424
+ () => buildTypes.find((b) => b.type === pendingBuildType)?.cost ?? 0,
20425
+ [buildTypes, pendingBuildType]
20426
+ );
20427
+ const buildingPositions = useMemo(
20428
+ () => new Set(buildings.map((b) => `${b.x},${b.y}`)),
20429
+ [buildings]
20430
+ );
20431
+ const validMoves = useMemo(() => {
20432
+ if (result !== "none" || gold < pendingCost) return [];
20433
+ return tiles.filter(
20434
+ (t2) => t2.passable !== false && !buildingPositions.has(`${t2.x},${t2.y}`)
20435
+ ).map((t2) => ({ x: t2.x, y: t2.y }));
20436
+ }, [tiles, buildingPositions, result, gold, pendingCost]);
20437
+ const isoTiles = useMemo(() => tilesToIso(tiles, assetManifest), [tiles, assetManifest]);
20438
+ const buildingFeatures = useMemo(() => buildingsToFeatures(buildings, assetManifest), [buildings, assetManifest]);
20439
+ const handleTileClick = useCallback((x, y) => {
20440
+ if (result !== "none") return;
20441
+ if (buildingPositions.has(`${x},${y}`)) return;
20442
+ if (gold < pendingCost) return;
20443
+ if (placeBuildingEvent) {
20444
+ eventBus.emit(`UI:${placeBuildingEvent}`, { x, y });
20445
+ }
20446
+ }, [result, buildingPositions, gold, pendingCost, placeBuildingEvent, eventBus]);
20447
+ const handleSelectBuildType = useCallback((buildType) => {
20448
+ if (selectBuildTypeEvent) {
20449
+ eventBus.emit(`UI:${selectBuildTypeEvent}`, { buildType });
20450
+ }
20451
+ }, [selectBuildTypeEvent, eventBus]);
20452
+ const canBuild = gold >= pendingCost && result === "none";
20453
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("city-builder-board relative min-h-[600px] bg-background", className), gap: "none", children: [
20454
+ /* @__PURE__ */ jsxs(
20455
+ HStack,
20456
+ {
20457
+ className: "px-4 py-2 border-b border-border bg-surface",
20458
+ gap: "lg",
20459
+ align: "center",
20460
+ children: [
20461
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
20462
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.gold") ?? "Gold" }),
20463
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
20464
+ ] }),
20465
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
20466
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.wood") ?? "Wood" }),
20467
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-success", children: wood })
20468
+ ] }),
20469
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
20470
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.population") ?? "Population" }),
20471
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: population })
20472
+ ] }),
20473
+ /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", className: "ml-auto", children: buildTypes.map((b) => /* @__PURE__ */ jsxs(
20474
+ Button,
20475
+ {
20476
+ variant: b.type === pendingBuildType ? "primary" : "secondary",
20477
+ size: "sm",
20478
+ disabled: gold < b.cost || result !== "none",
20479
+ onClick: () => handleSelectBuildType(b.type),
20480
+ children: [
20481
+ b.label,
20482
+ " (",
20483
+ b.cost,
20484
+ ")"
20485
+ ]
20486
+ },
20487
+ b.type
20488
+ )) })
20489
+ ]
20490
+ }
20491
+ ),
20492
+ /* @__PURE__ */ jsxs(Box, { className: "relative flex-1", children: [
20493
+ /* @__PURE__ */ jsx(
20494
+ IsometricCanvas_default,
20495
+ {
20496
+ tiles: isoTiles,
20497
+ features: buildingFeatures,
20498
+ assetBaseUrl: assetManifest?.baseUrl,
20499
+ assetManifest,
20500
+ validMoves,
20501
+ hoveredTile,
20502
+ onTileClick: handleTileClick,
20503
+ onTileHover: (x, y) => setHoveredTile({ x, y }),
20504
+ onTileLeave: () => setHoveredTile(null),
20505
+ scale,
20506
+ unitScale,
20507
+ spriteHeightRatio,
20508
+ spriteMaxWidthRatio
20509
+ }
20510
+ ),
20511
+ hoveredTile && canBuild && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsx(Typography, { variant: "small", children: t("cb.placeBuilding") ?? `Build ${pendingBuildType} (${pendingCost} gold)` }) })
20512
+ ] }),
20513
+ result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
20514
+ /* @__PURE__ */ jsx(
20515
+ Typography,
20516
+ {
20517
+ variant: "h2",
20518
+ className: cn(
20519
+ "text-4xl font-black tracking-widest uppercase",
20520
+ result === "won" ? "text-warning" : "text-error"
20521
+ ),
20522
+ children: result === "won" ? t("cb.victory") ?? "City Thrives!" : t("cb.defeat") ?? "City Collapsed!"
20523
+ }
20524
+ ),
20525
+ /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("cb.reachedGoal") ?? `Your city reached a population of ${population}.` : t("cb.bankrupt") ?? "Your city ran out of resources." })
20526
+ ] }) })
20527
+ ] });
20528
+ }
20529
+ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
20530
+ var init_CityBuilderBoard = __esm({
20531
+ "components/game/organisms/CityBuilderBoard.tsx"() {
20532
+ "use client";
20533
+ init_cn();
20534
+ init_useEventBus();
20535
+ init_Box();
20536
+ init_Button();
20537
+ init_Typography();
20538
+ init_Stack();
20539
+ init_IsometricCanvas();
20540
+ init_boardEntity();
20541
+ CB_GRID_W = 12;
20542
+ CB_GRID_H = 12;
20543
+ DEFAULT_BUILD_TYPES = [
20544
+ { type: "house", label: "House", cost: 20 },
20545
+ { type: "farm", label: "Farm", cost: 15 },
20546
+ { type: "mine", label: "Mine", cost: 25 },
20547
+ { type: "barracks", label: "Barracks", cost: 40 }
20548
+ ];
20549
+ DEFAULT_CB_TILES = buildDefaultCBTiles();
20550
+ CityBuilderBoard.displayName = "CityBuilderBoard";
20551
+ }
20552
+ });
20553
+ function isEntityRow2(value) {
20554
+ return value != null && typeof value === "object" && !Array.isArray(value);
20555
+ }
20556
+ function CityBuilderTemplate({
20557
+ entity,
20558
+ title = "City Builder",
20559
+ tiles,
20560
+ buildings,
20561
+ buildTypes,
20562
+ pendingBuildType,
20563
+ assetManifest,
20564
+ gold,
20565
+ wood,
20566
+ population,
20567
+ result,
20568
+ scale,
20569
+ unitScale,
20570
+ selectBuildTypeEvent,
20571
+ placeBuildingEvent,
20572
+ gameEndEvent,
20573
+ className
20574
+ }) {
20575
+ const resolved = isEntityRow2(entity) ? entity : void 0;
20576
+ return /* @__PURE__ */ jsxs(
20577
+ Box,
20578
+ {
20579
+ display: "flex",
20580
+ fullHeight: true,
20581
+ className: cn("city-builder-template flex-col", className),
20582
+ children: [
20583
+ /* @__PURE__ */ jsx(
20584
+ HStack,
20585
+ {
20586
+ gap: "sm",
20587
+ align: "center",
20588
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
20589
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
20590
+ }
20591
+ ),
20592
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
20593
+ CityBuilderBoard,
20594
+ {
20595
+ entity: resolved,
20596
+ tiles,
20597
+ buildings,
20598
+ buildTypes,
20599
+ pendingBuildType,
20600
+ assetManifest,
20601
+ gold,
20602
+ wood,
20603
+ population,
20604
+ result,
20605
+ scale,
20606
+ unitScale,
20607
+ selectBuildTypeEvent,
20608
+ placeBuildingEvent,
20609
+ gameEndEvent,
20610
+ className: "h-full"
20611
+ }
20612
+ ) })
20613
+ ]
20614
+ }
20615
+ );
20616
+ }
20617
+ var init_CityBuilderTemplate = __esm({
20618
+ "components/game/templates/CityBuilderTemplate.tsx"() {
20619
+ init_cn();
20620
+ init_Box();
20621
+ init_Stack();
20622
+ init_Typography();
20623
+ init_CityBuilderBoard();
20624
+ CityBuilderTemplate.displayName = "CityBuilderTemplate";
20625
+ }
20626
+ });
19936
20627
  function ClassifierBoard({
19937
20628
  entity,
19938
20629
  completeEvent = "PUZZLE_COMPLETE",
@@ -20911,7 +21602,7 @@ function CraftingRecipe({
20911
21602
  className
20912
21603
  }) {
20913
21604
  const eventBus = useEventBus();
20914
- const handleCraft = React76.useCallback(() => {
21605
+ const handleCraft = React79.useCallback(() => {
20915
21606
  onCraft?.();
20916
21607
  if (craftEvent) {
20917
21608
  eventBus.emit(craftEvent, { output: output.label });
@@ -20928,7 +21619,7 @@ function CraftingRecipe({
20928
21619
  children: [
20929
21620
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
20930
21621
  const hasSufficient = ingredient.available >= ingredient.required;
20931
- return /* @__PURE__ */ jsxs(React76.Fragment, { children: [
21622
+ return /* @__PURE__ */ jsxs(React79.Fragment, { children: [
20932
21623
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
20933
21624
  ItemSlot,
20934
21625
  {
@@ -21000,8 +21691,8 @@ function DPad({
21000
21691
  }) {
21001
21692
  const eventBus = useEventBus();
21002
21693
  const sizes = sizeMap6[size];
21003
- const [activeDirections, setActiveDirections] = React76.useState(/* @__PURE__ */ new Set());
21004
- const handlePress = React76.useCallback(
21694
+ const [activeDirections, setActiveDirections] = React79.useState(/* @__PURE__ */ new Set());
21695
+ const handlePress = React79.useCallback(
21005
21696
  (direction) => {
21006
21697
  setActiveDirections((prev) => new Set(prev).add(direction));
21007
21698
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -21009,7 +21700,7 @@ function DPad({
21009
21700
  },
21010
21701
  [directionEvent, eventBus, onDirection]
21011
21702
  );
21012
- const handleRelease = React76.useCallback(
21703
+ const handleRelease = React79.useCallback(
21013
21704
  (direction) => {
21014
21705
  setActiveDirections((prev) => {
21015
21706
  const next = new Set(prev);
@@ -21880,8 +22571,8 @@ var init_Menu = __esm({
21880
22571
  "bottom-end": "bottom-start"
21881
22572
  };
21882
22573
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
21883
- const triggerChild = React76__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
21884
- const triggerElement = React76__default.cloneElement(
22574
+ const triggerChild = React79__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
22575
+ const triggerElement = React79__default.cloneElement(
21885
22576
  triggerChild,
21886
22577
  {
21887
22578
  ref: triggerRef,
@@ -22015,14 +22706,14 @@ function useDataDnd(args) {
22015
22706
  const isZone = Boolean(dragGroup || accepts || sortable);
22016
22707
  const enabled = isZone || Boolean(dndRoot);
22017
22708
  const eventBus = useEventBus();
22018
- const parentRoot = React76__default.useContext(RootCtx);
22709
+ const parentRoot = React79__default.useContext(RootCtx);
22019
22710
  const isRoot = enabled && parentRoot === null;
22020
- const zoneId = React76__default.useId();
22711
+ const zoneId = React79__default.useId();
22021
22712
  const ownGroup = dragGroup ?? accepts ?? zoneId;
22022
- const [optimisticOrders, setOptimisticOrders] = React76__default.useState(() => /* @__PURE__ */ new Map());
22023
- const optimisticOrdersRef = React76__default.useRef(optimisticOrders);
22713
+ const [optimisticOrders, setOptimisticOrders] = React79__default.useState(() => /* @__PURE__ */ new Map());
22714
+ const optimisticOrdersRef = React79__default.useRef(optimisticOrders);
22024
22715
  optimisticOrdersRef.current = optimisticOrders;
22025
- const clearOptimisticOrder = React76__default.useCallback((group) => {
22716
+ const clearOptimisticOrder = React79__default.useCallback((group) => {
22026
22717
  setOptimisticOrders((prev) => {
22027
22718
  if (!prev.has(group)) return prev;
22028
22719
  const next = new Map(prev);
@@ -22047,7 +22738,7 @@ function useDataDnd(args) {
22047
22738
  const raw = it[dndItemIdField];
22048
22739
  return String(raw ?? `__idx_${idx}`);
22049
22740
  }).join("|");
22050
- const itemIds = React76__default.useMemo(
22741
+ const itemIds = React79__default.useMemo(
22051
22742
  () => orderedItems.map((it, idx) => {
22052
22743
  const raw = it[dndItemIdField];
22053
22744
  return raw ?? `__idx_${idx}`;
@@ -22055,7 +22746,7 @@ function useDataDnd(args) {
22055
22746
  [itemIdsSignature]
22056
22747
  );
22057
22748
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
22058
- React76__default.useEffect(() => {
22749
+ React79__default.useEffect(() => {
22059
22750
  const root = isRoot ? null : parentRoot;
22060
22751
  if (root) {
22061
22752
  root.clearOptimisticOrder(ownGroup);
@@ -22063,20 +22754,20 @@ function useDataDnd(args) {
22063
22754
  clearOptimisticOrder(ownGroup);
22064
22755
  }
22065
22756
  }, [itemsContentSig, ownGroup]);
22066
- const zonesRef = React76__default.useRef(/* @__PURE__ */ new Map());
22067
- const registerZone = React76__default.useCallback((zoneId2, meta2) => {
22757
+ const zonesRef = React79__default.useRef(/* @__PURE__ */ new Map());
22758
+ const registerZone = React79__default.useCallback((zoneId2, meta2) => {
22068
22759
  zonesRef.current.set(zoneId2, meta2);
22069
22760
  }, []);
22070
- const unregisterZone = React76__default.useCallback((zoneId2) => {
22761
+ const unregisterZone = React79__default.useCallback((zoneId2) => {
22071
22762
  zonesRef.current.delete(zoneId2);
22072
22763
  }, []);
22073
- const [activeDrag, setActiveDrag] = React76__default.useState(null);
22074
- const [overZoneGroup, setOverZoneGroup] = React76__default.useState(null);
22075
- const meta = React76__default.useMemo(
22764
+ const [activeDrag, setActiveDrag] = React79__default.useState(null);
22765
+ const [overZoneGroup, setOverZoneGroup] = React79__default.useState(null);
22766
+ const meta = React79__default.useMemo(
22076
22767
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
22077
22768
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
22078
22769
  );
22079
- React76__default.useEffect(() => {
22770
+ React79__default.useEffect(() => {
22080
22771
  const target = isRoot ? null : parentRoot;
22081
22772
  if (!target) {
22082
22773
  zonesRef.current.set(zoneId, meta);
@@ -22095,7 +22786,7 @@ function useDataDnd(args) {
22095
22786
  }, [parentRoot, isRoot, zoneId, meta]);
22096
22787
  const sensors = useAlmadarDndSensors(true);
22097
22788
  const collisionDetection = almadarDndCollisionDetection;
22098
- const findZoneByItem = React76__default.useCallback(
22789
+ const findZoneByItem = React79__default.useCallback(
22099
22790
  (id) => {
22100
22791
  for (const z of zonesRef.current.values()) {
22101
22792
  if (z.itemIds.includes(id)) return z;
@@ -22104,7 +22795,7 @@ function useDataDnd(args) {
22104
22795
  },
22105
22796
  []
22106
22797
  );
22107
- React76__default.useCallback(
22798
+ React79__default.useCallback(
22108
22799
  (group) => {
22109
22800
  for (const z of zonesRef.current.values()) {
22110
22801
  if (z.group === group) return z;
@@ -22113,7 +22804,7 @@ function useDataDnd(args) {
22113
22804
  },
22114
22805
  []
22115
22806
  );
22116
- const handleDragEnd = React76__default.useCallback(
22807
+ const handleDragEnd = React79__default.useCallback(
22117
22808
  (event) => {
22118
22809
  const { active, over } = event;
22119
22810
  const activeIdStr = String(active.id);
@@ -22204,8 +22895,8 @@ function useDataDnd(args) {
22204
22895
  },
22205
22896
  [eventBus]
22206
22897
  );
22207
- const sortableData = React76__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22208
- const SortableItem = React76__default.useCallback(
22898
+ const sortableData = React79__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22899
+ const SortableItem = React79__default.useCallback(
22209
22900
  ({ id, children }) => {
22210
22901
  const {
22211
22902
  attributes,
@@ -22245,7 +22936,7 @@ function useDataDnd(args) {
22245
22936
  id: droppableId,
22246
22937
  data: sortableData
22247
22938
  });
22248
- const ctx = React76__default.useContext(RootCtx);
22939
+ const ctx = React79__default.useContext(RootCtx);
22249
22940
  const activeDrag2 = ctx?.activeDrag ?? null;
22250
22941
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
22251
22942
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -22260,7 +22951,7 @@ function useDataDnd(args) {
22260
22951
  showForeignPlaceholder,
22261
22952
  ctxAvailable: ctx != null
22262
22953
  });
22263
- React76__default.useEffect(() => {
22954
+ React79__default.useEffect(() => {
22264
22955
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
22265
22956
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
22266
22957
  return /* @__PURE__ */ jsx(
@@ -22274,11 +22965,11 @@ function useDataDnd(args) {
22274
22965
  }
22275
22966
  );
22276
22967
  };
22277
- const rootContextValue = React76__default.useMemo(
22968
+ const rootContextValue = React79__default.useMemo(
22278
22969
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
22279
22970
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
22280
22971
  );
22281
- const handleDragStart = React76__default.useCallback((event) => {
22972
+ const handleDragStart = React79__default.useCallback((event) => {
22282
22973
  const sourceZone = findZoneByItem(event.active.id);
22283
22974
  const rect = event.active.rect.current.initial;
22284
22975
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -22297,7 +22988,7 @@ function useDataDnd(args) {
22297
22988
  isRoot
22298
22989
  });
22299
22990
  }, [findZoneByItem, isRoot, zoneId]);
22300
- const handleDragOver = React76__default.useCallback((event) => {
22991
+ const handleDragOver = React79__default.useCallback((event) => {
22301
22992
  const { active, over } = event;
22302
22993
  const overData = over?.data?.current;
22303
22994
  const overGroup = overData?.dndGroup ?? null;
@@ -22367,7 +23058,7 @@ function useDataDnd(args) {
22367
23058
  return next;
22368
23059
  });
22369
23060
  }, []);
22370
- const handleDragCancel = React76__default.useCallback((event) => {
23061
+ const handleDragCancel = React79__default.useCallback((event) => {
22371
23062
  setActiveDrag(null);
22372
23063
  setOverZoneGroup(null);
22373
23064
  dndLog.warn("dragCancel", {
@@ -22375,12 +23066,12 @@ function useDataDnd(args) {
22375
23066
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
22376
23067
  });
22377
23068
  }, []);
22378
- const handleDragEndWithCleanup = React76__default.useCallback((event) => {
23069
+ const handleDragEndWithCleanup = React79__default.useCallback((event) => {
22379
23070
  handleDragEnd(event);
22380
23071
  setActiveDrag(null);
22381
23072
  setOverZoneGroup(null);
22382
23073
  }, [handleDragEnd]);
22383
- const wrapContainer = React76__default.useCallback(
23074
+ const wrapContainer = React79__default.useCallback(
22384
23075
  (children) => {
22385
23076
  if (!enabled) return children;
22386
23077
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -22434,7 +23125,7 @@ var init_useDataDnd = __esm({
22434
23125
  init_useAlmadarDndCollision();
22435
23126
  init_Box();
22436
23127
  dndLog = createLogger("almadar:ui:dnd");
22437
- RootCtx = React76__default.createContext(null);
23128
+ RootCtx = React79__default.createContext(null);
22438
23129
  }
22439
23130
  });
22440
23131
  function renderIconInput(icon, props) {
@@ -22960,7 +23651,7 @@ function DataList({
22960
23651
  }) {
22961
23652
  const eventBus = useEventBus();
22962
23653
  const { t } = useTranslate();
22963
- const [visibleCount, setVisibleCount] = React76__default.useState(pageSize || Infinity);
23654
+ const [visibleCount, setVisibleCount] = React79__default.useState(pageSize || Infinity);
22964
23655
  const fieldDefs = fields ?? columns ?? [];
22965
23656
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
22966
23657
  const dnd = useDataDnd({
@@ -22979,7 +23670,7 @@ function DataList({
22979
23670
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
22980
23671
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
22981
23672
  const hasRenderProp = typeof children === "function";
22982
- React76__default.useEffect(() => {
23673
+ React79__default.useEffect(() => {
22983
23674
  const renderItemTypeOf = typeof schemaRenderItem;
22984
23675
  const childrenTypeOf = typeof children;
22985
23676
  if (data.length > 0 && !hasRenderProp) {
@@ -23084,7 +23775,7 @@ function DataList({
23084
23775
  const items2 = data.map((item) => item);
23085
23776
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
23086
23777
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
23087
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
23778
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
23088
23779
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
23089
23780
  group.items.map((itemData, index) => {
23090
23781
  const id = itemData.id || `${gi}-${index}`;
@@ -23225,7 +23916,7 @@ function DataList({
23225
23916
  className
23226
23917
  ),
23227
23918
  children: [
23228
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
23919
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
23229
23920
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
23230
23921
  group.items.map(
23231
23922
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -23332,8 +24023,8 @@ function ScalarControl({
23332
24023
  }
23333
24024
  const numeric = typeof value === "number";
23334
24025
  const initial = value === null ? "" : String(value);
23335
- const [draft, setDraft] = React76__default.useState(initial);
23336
- React76__default.useEffect(() => setDraft(initial), [initial]);
24026
+ const [draft, setDraft] = React79__default.useState(initial);
24027
+ React79__default.useEffect(() => setDraft(initial), [initial]);
23337
24028
  const commit = () => {
23338
24029
  if (numeric) {
23339
24030
  const n = draft.trim() === "" ? 0 : Number(draft);
@@ -23401,8 +24092,8 @@ function Row({
23401
24092
  onRemove,
23402
24093
  readonly
23403
24094
  }) {
23404
- const [keyDraft, setKeyDraft] = React76__default.useState(rowKey);
23405
- React76__default.useEffect(() => setKeyDraft(rowKey), [rowKey]);
24095
+ const [keyDraft, setKeyDraft] = React79__default.useState(rowKey);
24096
+ React79__default.useEffect(() => setKeyDraft(rowKey), [rowKey]);
23406
24097
  const container = isObj(value) || isArr(value);
23407
24098
  return /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "group w-max min-w-full", children: [
23408
24099
  /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", className: "py-0.5 w-max", children: [
@@ -23445,7 +24136,7 @@ function ContainerNode({
23445
24136
  depth,
23446
24137
  readonly
23447
24138
  }) {
23448
- const [open, setOpen] = React76__default.useState(depth < 2);
24139
+ const [open, setOpen] = React79__default.useState(depth < 2);
23449
24140
  const array = isArr(value);
23450
24141
  const entries = array ? value.map((v, i) => [String(i), v]) : Object.entries(value);
23451
24142
  const setObjValue = (key, next) => {
@@ -23587,7 +24278,7 @@ var init_FormSection = __esm({
23587
24278
  columns = 1,
23588
24279
  className
23589
24280
  }) => {
23590
- const [collapsed, setCollapsed] = React76__default.useState(defaultCollapsed);
24281
+ const [collapsed, setCollapsed] = React79__default.useState(defaultCollapsed);
23591
24282
  const { t } = useTranslate();
23592
24283
  const eventBus = useEventBus();
23593
24284
  const gridClass = {
@@ -23595,7 +24286,7 @@ var init_FormSection = __esm({
23595
24286
  2: "grid-cols-1 md:grid-cols-2",
23596
24287
  3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
23597
24288
  }[columns];
23598
- React76__default.useCallback(() => {
24289
+ React79__default.useCallback(() => {
23599
24290
  if (collapsible) {
23600
24291
  setCollapsed((prev) => !prev);
23601
24292
  eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
@@ -24003,8 +24694,8 @@ function TextLikeControl({
24003
24694
  onCommit
24004
24695
  }) {
24005
24696
  const initial = value === void 0 || value === null ? "" : String(value);
24006
- const [draft, setDraft] = React76__default.useState(initial);
24007
- React76__default.useEffect(() => setDraft(initial), [initial]);
24697
+ const [draft, setDraft] = React79__default.useState(initial);
24698
+ React79__default.useEffect(() => setDraft(initial), [initial]);
24008
24699
  const commit = () => {
24009
24700
  if (numeric) {
24010
24701
  const n = draft.trim() === "" ? 0 : Number(draft);
@@ -24170,14 +24861,14 @@ var init_NodeSlotEditor = __esm({
24170
24861
  isObj2 = (v) => v !== null && v !== void 0 && typeof v === "object" && !Array.isArray(v);
24171
24862
  NodeSlotEditor = ({ value, onChange, className }) => {
24172
24863
  const { type, props, wasArray } = normalize(value);
24173
- const patterns = React76__default.useMemo(() => {
24864
+ const patterns = React79__default.useMemo(() => {
24174
24865
  try {
24175
24866
  return [...getKnownPatterns()].sort();
24176
24867
  } catch {
24177
24868
  return [];
24178
24869
  }
24179
24870
  }, []);
24180
- const options = React76__default.useMemo(
24871
+ const options = React79__default.useMemo(
24181
24872
  () => [{ value: "", label: "\u2014 none \u2014" }, ...patterns.map((p2) => ({ value: p2, label: p2 }))],
24182
24873
  [patterns]
24183
24874
  );
@@ -24189,7 +24880,7 @@ var init_NodeSlotEditor = __esm({
24189
24880
  const pattern = { type: nextType, ...nextProps };
24190
24881
  onChange(wasArray || value === void 0 ? [pattern] : pattern);
24191
24882
  };
24192
- const schemaEntries = React76__default.useMemo(() => {
24883
+ const schemaEntries = React79__default.useMemo(() => {
24193
24884
  if (!type) return [];
24194
24885
  const def = getPatternDefinition(type);
24195
24886
  if (!def?.propsSchema) return [];
@@ -25083,7 +25774,7 @@ var init_Grid = __esm({
25083
25774
  as: Component2 = "div"
25084
25775
  }) => {
25085
25776
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
25086
- return React76__default.createElement(
25777
+ return React79__default.createElement(
25087
25778
  Component2,
25088
25779
  {
25089
25780
  className: cn(
@@ -25271,8 +25962,8 @@ var init_Popover = __esm({
25271
25962
  onMouseEnter: handleOpen,
25272
25963
  onMouseLeave: handleClose
25273
25964
  };
25274
- const childElement = React76__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25275
- const triggerElement = React76__default.cloneElement(
25965
+ const childElement = React79__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25966
+ const triggerElement = React79__default.cloneElement(
25276
25967
  childElement,
25277
25968
  {
25278
25969
  ref: triggerRef,
@@ -26112,8 +26803,8 @@ var init_Tooltip = __esm({
26112
26803
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
26113
26804
  };
26114
26805
  }, []);
26115
- const triggerElement = React76__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
26116
- const trigger = React76__default.cloneElement(triggerElement, {
26806
+ const triggerElement = React79__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
26807
+ const trigger = React79__default.cloneElement(triggerElement, {
26117
26808
  ref: triggerRef,
26118
26809
  onMouseEnter: handleMouseEnter,
26119
26810
  onMouseLeave: handleMouseLeave,
@@ -26199,7 +26890,7 @@ var init_WizardProgress = __esm({
26199
26890
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
26200
26891
  const isActive = index === currentStep;
26201
26892
  const isCompleted = index < currentStep;
26202
- return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
26893
+ return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
26203
26894
  /* @__PURE__ */ jsx(
26204
26895
  "button",
26205
26896
  {
@@ -27244,9 +27935,9 @@ function ScoreDisplay({
27244
27935
  ...rest
27245
27936
  }) {
27246
27937
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
27247
- const [displayValue, setDisplayValue] = React76.useState(resolvedValue);
27248
- const [isAnimating, setIsAnimating] = React76.useState(false);
27249
- React76.useEffect(() => {
27938
+ const [displayValue, setDisplayValue] = React79.useState(resolvedValue);
27939
+ const [isAnimating, setIsAnimating] = React79.useState(false);
27940
+ React79.useEffect(() => {
27250
27941
  if (!animated || displayValue === resolvedValue) {
27251
27942
  setDisplayValue(resolvedValue);
27252
27943
  return;
@@ -27314,7 +28005,7 @@ var init_ScoreDisplay = __esm({
27314
28005
  }
27315
28006
  });
27316
28007
  function StatBadge({
27317
- assetUrl = DEFAULT_ASSET_URL7,
28008
+ assetUrl,
27318
28009
  label,
27319
28010
  value = 0,
27320
28011
  max,
@@ -27381,7 +28072,7 @@ function StatBadge({
27381
28072
  }
27382
28073
  );
27383
28074
  }
27384
- var sizeMap11, variantMap2, DEFAULT_ASSET_URL7;
28075
+ var sizeMap11, variantMap2;
27385
28076
  var init_StatBadge = __esm({
27386
28077
  "components/game/molecules/StatBadge.tsx"() {
27387
28078
  init_cn();
@@ -27400,7 +28091,6 @@ var init_StatBadge = __esm({
27400
28091
  warning: "bg-warning/15 border-warning/40 text-foreground",
27401
28092
  danger: "bg-error/15 border-error/40 text-foreground"
27402
28093
  };
27403
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
27404
28094
  StatBadge.displayName = "StatBadge";
27405
28095
  }
27406
28096
  });
@@ -27417,7 +28107,7 @@ function InventoryGrid({
27417
28107
  const eventBus = useEventBus();
27418
28108
  const slotCount = totalSlots ?? items.length;
27419
28109
  const emptySlotCount = Math.max(0, slotCount - items.length);
27420
- const handleSelect = React76.useCallback(
28110
+ const handleSelect = React79.useCallback(
27421
28111
  (id) => {
27422
28112
  onSelect?.(id);
27423
28113
  if (selectEvent) {
@@ -27484,7 +28174,7 @@ var init_InventoryGrid = __esm({
27484
28174
  }
27485
28175
  });
27486
28176
  function WaypointMarker({
27487
- assetUrl = DEFAULT_ASSET_URL8,
28177
+ assetUrl = DEFAULT_ASSET_URL7,
27488
28178
  label,
27489
28179
  icon,
27490
28180
  active = true,
@@ -27550,12 +28240,12 @@ function WaypointMarker({
27550
28240
  )
27551
28241
  ] });
27552
28242
  }
27553
- var DEFAULT_ASSET_URL8, sizeMap12, checkIcon;
28243
+ var DEFAULT_ASSET_URL7, sizeMap12, checkIcon;
27554
28244
  var init_WaypointMarker = __esm({
27555
28245
  "components/game/atoms/WaypointMarker.tsx"() {
27556
28246
  init_cn();
27557
28247
  init_Icon();
27558
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
28248
+ DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
27559
28249
  sizeMap12 = {
27560
28250
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
27561
28251
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -27730,35 +28420,37 @@ function GameCanvas2D({
27730
28420
  drawEvent,
27731
28421
  fps = 60,
27732
28422
  backgroundImage = "",
27733
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
28423
+ assetBaseUrl,
27734
28424
  className
27735
28425
  }) {
27736
- const canvasRef = React76.useRef(null);
27737
- const rafRef = React76.useRef(0);
27738
- const frameRef = React76.useRef(0);
27739
- const lastTimeRef = React76.useRef(0);
27740
- const imageCache = React76.useRef(/* @__PURE__ */ new Map());
28426
+ const canvasRef = React79.useRef(null);
28427
+ const rafRef = React79.useRef(0);
28428
+ const frameRef = React79.useRef(0);
28429
+ const lastTimeRef = React79.useRef(0);
28430
+ const imageCache = React79.useRef(/* @__PURE__ */ new Map());
27741
28431
  const emit = useEmitEvent();
27742
- const onDrawRef = React76.useRef(onDraw);
28432
+ const onDrawRef = React79.useRef(onDraw);
27743
28433
  onDrawRef.current = onDraw;
27744
- const onTickRef = React76.useRef(onTick);
28434
+ const onTickRef = React79.useRef(onTick);
27745
28435
  onTickRef.current = onTick;
27746
- const tickEventRef = React76.useRef(tickEvent);
28436
+ const tickEventRef = React79.useRef(tickEvent);
27747
28437
  tickEventRef.current = tickEvent;
27748
- const drawEventRef = React76.useRef(drawEvent);
28438
+ const drawEventRef = React79.useRef(drawEvent);
27749
28439
  drawEventRef.current = drawEvent;
27750
- const emitRef = React76.useRef(emit);
28440
+ const emitRef = React79.useRef(emit);
27751
28441
  emitRef.current = emit;
27752
- const assetBaseUrlRef = React76.useRef(assetBaseUrl);
28442
+ const assetBaseUrlRef = React79.useRef(assetBaseUrl);
27753
28443
  assetBaseUrlRef.current = assetBaseUrl;
27754
- const backgroundImageRef = React76.useRef(backgroundImage);
28444
+ const backgroundImageRef = React79.useRef(backgroundImage);
27755
28445
  backgroundImageRef.current = backgroundImage;
27756
- const widthRef = React76.useRef(width);
28446
+ const widthRef = React79.useRef(width);
27757
28447
  widthRef.current = width;
27758
- const heightRef = React76.useRef(height);
28448
+ const heightRef = React79.useRef(height);
27759
28449
  heightRef.current = height;
27760
- const loadImage = React76.useCallback((url) => {
27761
- const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
28450
+ const loadImage = React79.useCallback((url) => {
28451
+ const base = assetBaseUrlRef.current;
28452
+ if (!url.startsWith("http") && !base) return null;
28453
+ const fullUrl = url.startsWith("http") ? url : `${base}${url}`;
27762
28454
  const cached = imageCache.current.get(fullUrl);
27763
28455
  if (cached?.complete && cached.naturalWidth > 0) return cached;
27764
28456
  if (!cached) {
@@ -27769,7 +28461,7 @@ function GameCanvas2D({
27769
28461
  }
27770
28462
  return null;
27771
28463
  }, []);
27772
- React76.useEffect(() => {
28464
+ React79.useEffect(() => {
27773
28465
  const canvas = canvasRef.current;
27774
28466
  if (!canvas) return;
27775
28467
  const ctx = canvas.getContext("2d");
@@ -28073,7 +28765,7 @@ var init_ResourceBar = __esm({
28073
28765
  }
28074
28766
  });
28075
28767
  function TurnIndicator({
28076
- assetUrl = DEFAULT_ASSET_URL9,
28768
+ assetUrl = DEFAULT_ASSET_URL8,
28077
28769
  currentTurn = 1,
28078
28770
  maxTurns,
28079
28771
  activeTeam,
@@ -28123,7 +28815,7 @@ function TurnIndicator({
28123
28815
  }
28124
28816
  );
28125
28817
  }
28126
- var sizeMap14, DEFAULT_ASSET_URL9;
28818
+ var sizeMap14, DEFAULT_ASSET_URL8;
28127
28819
  var init_TurnIndicator = __esm({
28128
28820
  "components/game/atoms/TurnIndicator.tsx"() {
28129
28821
  init_cn();
@@ -28132,7 +28824,7 @@ var init_TurnIndicator = __esm({
28132
28824
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
28133
28825
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
28134
28826
  };
28135
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
28827
+ DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
28136
28828
  TurnIndicator.displayName = "TurnIndicator";
28137
28829
  }
28138
28830
  });
@@ -28145,7 +28837,7 @@ function TurnPanel({
28145
28837
  className
28146
28838
  }) {
28147
28839
  const eventBus = useEventBus();
28148
- const handleAction = React76.useCallback(
28840
+ const handleAction = React79.useCallback(
28149
28841
  (event) => {
28150
28842
  if (event) {
28151
28843
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -28203,7 +28895,7 @@ var init_TurnPanel = __esm({
28203
28895
  }
28204
28896
  });
28205
28897
  function EnemyPlate({
28206
- assetUrl = DEFAULT_ASSET_URL10,
28898
+ assetUrl,
28207
28899
  name = "Shadow Guard",
28208
28900
  health = 80,
28209
28901
  maxHealth = 100,
@@ -28287,7 +28979,7 @@ function EnemyPlate({
28287
28979
  }
28288
28980
  );
28289
28981
  }
28290
- var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL10;
28982
+ var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
28291
28983
  var init_EnemyPlate = __esm({
28292
28984
  "components/game/molecules/EnemyPlate.tsx"() {
28293
28985
  "use client";
@@ -28304,7 +28996,6 @@ var init_EnemyPlate = __esm({
28304
28996
  DEFAULT_ENEMY_EFFECTS = [
28305
28997
  { icon: "flame", label: "Burn", variant: "debuff" }
28306
28998
  ];
28307
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
28308
28999
  EnemyPlate.displayName = "EnemyPlate";
28309
29000
  }
28310
29001
  });
@@ -28314,7 +29005,7 @@ function UnitCommandBar({
28314
29005
  className
28315
29006
  }) {
28316
29007
  const eventBus = useEventBus();
28317
- const handleCommand = React76.useCallback(
29008
+ const handleCommand = React79.useCallback(
28318
29009
  (event) => {
28319
29010
  if (event) {
28320
29011
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -28455,6 +29146,9 @@ function DialogueBox({
28455
29146
  completeEvent,
28456
29147
  choiceEvent,
28457
29148
  advanceEvent,
29149
+ backgroundImage,
29150
+ portraitUrl,
29151
+ portraitScale = 1,
28458
29152
  className
28459
29153
  }) {
28460
29154
  const eventBus = useEventBus();
@@ -28570,64 +29264,98 @@ function DialogueBox({
28570
29264
  }
28571
29265
  }, [isTyping, skipTypewriter, dialogue.choices, selectedChoice, onChoice, onAdvance, choiceEvent, advanceEvent, eventBus]);
28572
29266
  const enabledChoices = dialogue.choices?.filter((c) => !c.disabled) ?? [];
28573
- return /* @__PURE__ */ jsx(
28574
- "div",
28575
- {
28576
- className: cn(
28577
- "fixed left-0 right-0 z-40",
28578
- position === "top" ? "top-0" : "bottom-0",
28579
- className
28580
- ),
28581
- onClick: handleClick,
28582
- onKeyDown: handleKeyDown,
28583
- tabIndex: 0,
28584
- role: "dialog",
28585
- "aria-label": "Dialogue",
28586
- children: /* @__PURE__ */ jsx("div", { className: "mx-4 my-4 bg-[var(--color-card)] bg-opacity-95 border-2 border-border rounded-container overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
28587
- dialogue.portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-4 border-r border-border", children: /* @__PURE__ */ jsx(
29267
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
29268
+ backgroundImage && /* @__PURE__ */ jsx(
29269
+ "div",
29270
+ {
29271
+ className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
29272
+ style: { backgroundImage: `url(${backgroundImage})` },
29273
+ "aria-hidden": "true"
29274
+ }
29275
+ ),
29276
+ portraitUrl && /* @__PURE__ */ jsx(
29277
+ "div",
29278
+ {
29279
+ className: cn(
29280
+ "fixed left-1/2 -translate-x-1/2 z-30 pointer-events-none flex items-end",
29281
+ position === "top" ? "top-0" : "bottom-0"
29282
+ ),
29283
+ style: { height: `${60 * portraitScale}vh` },
29284
+ children: /* @__PURE__ */ jsx(
28588
29285
  "img",
28589
29286
  {
28590
- src: dialogue.portrait,
29287
+ src: portraitUrl,
28591
29288
  alt: dialogue.speaker,
28592
- className: "w-24 h-24 object-contain",
28593
- style: { imageRendering: "pixelated" }
29289
+ className: "h-full w-auto object-contain drop-shadow-2xl"
28594
29290
  }
28595
- ) }),
28596
- /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4", children: [
28597
- /* @__PURE__ */ jsx("div", { className: "text-warning font-bold mb-2", children: dialogue.speaker }),
28598
- /* @__PURE__ */ jsxs("div", { className: "text-[var(--color-foreground)] text-lg leading-relaxed min-h-[60px]", children: [
28599
- displayedText,
28600
- isTyping && /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "\u258C" })
28601
- ] }),
28602
- !isTyping && enabledChoices.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: enabledChoices.map((choice, index) => /* @__PURE__ */ jsxs(
28603
- "button",
29291
+ )
29292
+ }
29293
+ ),
29294
+ /* @__PURE__ */ jsx(
29295
+ "div",
29296
+ {
29297
+ className: cn(
29298
+ "fixed left-0 right-0 z-40",
29299
+ position === "top" ? "top-0" : "bottom-0",
29300
+ className
29301
+ ),
29302
+ onClick: handleClick,
29303
+ onKeyDown: handleKeyDown,
29304
+ tabIndex: 0,
29305
+ role: "dialog",
29306
+ "aria-label": "Dialogue",
29307
+ children: /* @__PURE__ */ jsx("div", { className: cn(
29308
+ "mx-4 my-4 border-2 rounded-container overflow-hidden",
29309
+ backgroundImage ? "bg-black/80 backdrop-blur-sm text-white border-white/20" : "bg-[var(--color-card)] bg-opacity-95 border-border"
29310
+ ), children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
29311
+ dialogue.portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-4 border-r border-border", children: /* @__PURE__ */ jsx(
29312
+ "img",
28604
29313
  {
28605
- type: "button",
28606
- className: cn(
28607
- "block w-full text-left px-4 py-2 rounded-interactive transition-colors",
28608
- "hover:bg-[var(--color-surface,#374151)] focus:outline-none focus:ring-2 focus:ring-warning",
28609
- selectedChoice === index ? "bg-[var(--color-surface,#374151)] text-warning" : "bg-[var(--color-card)] text-[var(--color-foreground)]"
28610
- ),
28611
- onClick: (e) => {
28612
- e.stopPropagation();
28613
- if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
28614
- onChoice?.(choice);
29314
+ src: dialogue.portrait,
29315
+ alt: dialogue.speaker,
29316
+ className: "w-24 h-24 object-contain",
29317
+ style: { imageRendering: "pixelated" }
29318
+ }
29319
+ ) }),
29320
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4", children: [
29321
+ /* @__PURE__ */ jsx("div", { className: "text-warning font-bold mb-2", children: dialogue.speaker }),
29322
+ /* @__PURE__ */ jsxs("div", { className: cn(
29323
+ "text-lg leading-relaxed min-h-[60px]",
29324
+ backgroundImage ? "text-white" : "text-[var(--color-foreground)]"
29325
+ ), children: [
29326
+ displayedText,
29327
+ isTyping && /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "\u258C" })
29328
+ ] }),
29329
+ !isTyping && enabledChoices.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: enabledChoices.map((choice, index) => /* @__PURE__ */ jsxs(
29330
+ "button",
29331
+ {
29332
+ type: "button",
29333
+ className: cn(
29334
+ "block w-full text-left px-4 py-2 rounded-interactive transition-colors",
29335
+ "hover:bg-[var(--color-surface,#374151)] focus:outline-none focus:ring-2 focus:ring-warning",
29336
+ selectedChoice === index ? "bg-[var(--color-surface,#374151)] text-warning" : backgroundImage ? "bg-white/10 text-white hover:bg-white/20" : "bg-[var(--color-card)] text-[var(--color-foreground)]"
29337
+ ),
29338
+ onClick: (e) => {
29339
+ e.stopPropagation();
29340
+ if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
29341
+ onChoice?.(choice);
29342
+ },
29343
+ children: [
29344
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground mr-2", children: [
29345
+ index + 1,
29346
+ "."
29347
+ ] }),
29348
+ choice.text
29349
+ ]
28615
29350
  },
28616
- children: [
28617
- /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground mr-2", children: [
28618
- index + 1,
28619
- "."
28620
- ] }),
28621
- choice.text
28622
- ]
28623
- },
28624
- index
28625
- )) }),
28626
- !isTyping && !dialogue.choices?.length && /* @__PURE__ */ jsx("div", { className: "mt-4 text-muted-foreground text-sm animate-pulse", children: "Press SPACE or click to continue..." })
28627
- ] })
28628
- ] }) })
28629
- }
28630
- );
29351
+ index
29352
+ )) }),
29353
+ !isTyping && !dialogue.choices?.length && /* @__PURE__ */ jsx("div", { className: "mt-4 text-muted-foreground text-sm animate-pulse", children: "Press SPACE or click to continue..." })
29354
+ ] })
29355
+ ] }) })
29356
+ }
29357
+ )
29358
+ ] });
28631
29359
  }
28632
29360
  var DEFAULT_DIALOGUE;
28633
29361
  var init_DialogueBox = __esm({
@@ -28828,7 +29556,7 @@ function GameMenu({
28828
29556
  } catch {
28829
29557
  }
28830
29558
  const eventBus = eventBusProp || eventBusFromHook;
28831
- const handleOptionClick = React76.useCallback(
29559
+ const handleOptionClick = React79.useCallback(
28832
29560
  (option) => {
28833
29561
  if (option.event && eventBus) {
28834
29562
  eventBus.emit(`UI:${option.event}`, { option });
@@ -28947,7 +29675,7 @@ function GameOverScreen({
28947
29675
  } catch {
28948
29676
  }
28949
29677
  const eventBus = eventBusProp || eventBusFromHook;
28950
- const handleActionClick = React76.useCallback(
29678
+ const handleActionClick = React79.useCallback(
28951
29679
  (action) => {
28952
29680
  if (action.event && eventBus) {
28953
29681
  eventBus.emit(`UI:${action.event}`, { action });
@@ -29154,10 +29882,10 @@ function PlatformerCanvas({
29154
29882
  canvasHeight = 400,
29155
29883
  followCamera = true,
29156
29884
  bgColor = "#5c94fc",
29157
- playerSprite = "https://almadar-kflow-assets.web.app/shared/platformer/characters/platformChar_idle.png",
29885
+ playerSprite,
29158
29886
  tileSprites,
29159
29887
  backgroundImage = "",
29160
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/platformer/",
29888
+ assetBaseUrl,
29161
29889
  leftEvent = "MOVE_LEFT",
29162
29890
  rightEvent = "MOVE_RIGHT",
29163
29891
  jumpEvent = "JUMP",
@@ -29171,6 +29899,7 @@ function PlatformerCanvas({
29171
29899
  const imageCache = useRef(/* @__PURE__ */ new Map());
29172
29900
  const [loadedImages, setLoadedImages] = useState(/* @__PURE__ */ new Set());
29173
29901
  const loadImage = useCallback((url) => {
29902
+ if (!url.startsWith("http") && !assetBaseUrl) return null;
29174
29903
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
29175
29904
  const cached = imageCache.current.get(fullUrl);
29176
29905
  if (cached?.complete && cached.naturalWidth > 0) {
@@ -29509,6 +30238,7 @@ var init_molecules = __esm({
29509
30238
  init_ActionButtons();
29510
30239
  init_StatBadge();
29511
30240
  init_InventoryGrid();
30241
+ init_CardHand();
29512
30242
  init_QuestTracker();
29513
30243
  init_CraftingRecipe();
29514
30244
  init_PowerupSlots();
@@ -29891,13 +30621,13 @@ var init_MapView = __esm({
29891
30621
  shadowSize: [41, 41]
29892
30622
  });
29893
30623
  L.Marker.prototype.options.icon = defaultIcon;
29894
- const { useEffect: useEffect81, useRef: useRef78, useCallback: useCallback120, useState: useState110 } = React76__default;
30624
+ const { useEffect: useEffect82, useRef: useRef81, useCallback: useCallback125, useState: useState111 } = React79__default;
29895
30625
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29896
30626
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29897
30627
  function MapUpdater({ centerLat, centerLng, zoom }) {
29898
30628
  const map = useMap();
29899
- const prevRef = useRef78({ centerLat, centerLng, zoom });
29900
- useEffect81(() => {
30629
+ const prevRef = useRef81({ centerLat, centerLng, zoom });
30630
+ useEffect82(() => {
29901
30631
  const prev = prevRef.current;
29902
30632
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
29903
30633
  map.setView([centerLat, centerLng], zoom);
@@ -29908,7 +30638,7 @@ var init_MapView = __esm({
29908
30638
  }
29909
30639
  function MapClickHandler({ onMapClick }) {
29910
30640
  const map = useMap();
29911
- useEffect81(() => {
30641
+ useEffect82(() => {
29912
30642
  if (!onMapClick) return;
29913
30643
  const handler = (e) => {
29914
30644
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -29936,8 +30666,8 @@ var init_MapView = __esm({
29936
30666
  showAttribution = true
29937
30667
  }) {
29938
30668
  const eventBus = useEventBus3();
29939
- const [clickedPosition, setClickedPosition] = useState110(null);
29940
- const handleMapClick = useCallback120((lat, lng) => {
30669
+ const [clickedPosition, setClickedPosition] = useState111(null);
30670
+ const handleMapClick = useCallback125((lat, lng) => {
29941
30671
  if (showClickedPin) {
29942
30672
  setClickedPosition({ lat, lng });
29943
30673
  }
@@ -29946,7 +30676,7 @@ var init_MapView = __esm({
29946
30676
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
29947
30677
  }
29948
30678
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
29949
- const handleMarkerClick = useCallback120((marker) => {
30679
+ const handleMarkerClick = useCallback125((marker) => {
29950
30680
  onMarkerClick?.(marker);
29951
30681
  if (markerClickEvent) {
29952
30682
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -30797,8 +31527,8 @@ function TableView({
30797
31527
  }) {
30798
31528
  const eventBus = useEventBus();
30799
31529
  const { t } = useTranslate();
30800
- const [visibleCount, setVisibleCount] = React76__default.useState(pageSize > 0 ? pageSize : Infinity);
30801
- const [localSelected, setLocalSelected] = React76__default.useState(/* @__PURE__ */ new Set());
31530
+ const [visibleCount, setVisibleCount] = React79__default.useState(pageSize > 0 ? pageSize : Infinity);
31531
+ const [localSelected, setLocalSelected] = React79__default.useState(/* @__PURE__ */ new Set());
30802
31532
  const colDefs = columns ?? fields ?? [];
30803
31533
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
30804
31534
  const dnd = useDataDnd({
@@ -30993,12 +31723,12 @@ function TableView({
30993
31723
  ]
30994
31724
  }
30995
31725
  );
30996
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React76__default.Fragment, { children: rowInner }, id);
31726
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React79__default.Fragment, { children: rowInner }, id);
30997
31727
  };
30998
31728
  const items = data.map((row) => row);
30999
31729
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
31000
31730
  let runningIndex = 0;
31001
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
31731
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
31002
31732
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
31003
31733
  group.items.map((row) => renderRow(row, runningIndex++))
31004
31734
  ] }, gi)) });
@@ -32355,7 +33085,7 @@ var init_StepFlow = __esm({
32355
33085
  className
32356
33086
  }) => {
32357
33087
  if (orientation === "vertical") {
32358
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React76__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
33088
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React79__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
32359
33089
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
32360
33090
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
32361
33091
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -32366,7 +33096,7 @@ var init_StepFlow = __esm({
32366
33096
  ] })
32367
33097
  ] }) }, index)) });
32368
33098
  }
32369
- return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
33099
+ return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
32370
33100
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
32371
33101
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
32372
33102
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -33351,7 +34081,7 @@ var init_LikertScale = __esm({
33351
34081
  md: "text-base",
33352
34082
  lg: "text-lg"
33353
34083
  };
33354
- LikertScale = React76__default.forwardRef(
34084
+ LikertScale = React79__default.forwardRef(
33355
34085
  ({
33356
34086
  question,
33357
34087
  options = DEFAULT_LIKERT_OPTIONS,
@@ -33363,7 +34093,7 @@ var init_LikertScale = __esm({
33363
34093
  variant = "radios",
33364
34094
  className
33365
34095
  }, ref) => {
33366
- const groupId = React76__default.useId();
34096
+ const groupId = React79__default.useId();
33367
34097
  const eventBus = useEventBus();
33368
34098
  const handleSelect = useCallback(
33369
34099
  (next) => {
@@ -35645,7 +36375,7 @@ var init_DocBreadcrumb = __esm({
35645
36375
  "aria-label": t("aria.breadcrumb"),
35646
36376
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
35647
36377
  const isLast = idx === items.length - 1;
35648
- return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
36378
+ return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
35649
36379
  idx > 0 && /* @__PURE__ */ jsx(
35650
36380
  Icon,
35651
36381
  {
@@ -36514,7 +37244,7 @@ var init_MiniStateMachine = __esm({
36514
37244
  const x = 2 + i * (NODE_W + GAP2 + ARROW_W + GAP2);
36515
37245
  const tc = transitionCounts[s.name] ?? 0;
36516
37246
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
36517
- return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
37247
+ return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
36518
37248
  /* @__PURE__ */ jsx(
36519
37249
  AvlState,
36520
37250
  {
@@ -36718,7 +37448,7 @@ var init_PageHeader = __esm({
36718
37448
  info: "bg-info/10 text-info"
36719
37449
  };
36720
37450
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
36721
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
37451
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
36722
37452
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
36723
37453
  crumb.href ? /* @__PURE__ */ jsx(
36724
37454
  "a",
@@ -37400,8 +38130,8 @@ var init_WizardContainer = __esm({
37400
38130
  return void 0;
37401
38131
  if (typeof controlledStep === "number") return controlledStep;
37402
38132
  if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
37403
- const num2 = Number(controlledStep);
37404
- return isNaN(num2) ? void 0 : num2;
38133
+ const num3 = Number(controlledStep);
38134
+ return isNaN(num3) ? void 0 : num3;
37405
38135
  })();
37406
38136
  const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
37407
38137
  const totalSteps = steps.length;
@@ -37447,7 +38177,7 @@ var init_WizardContainer = __esm({
37447
38177
  const isCompleted = index < currentStep;
37448
38178
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
37449
38179
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
37450
- return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
38180
+ return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
37451
38181
  /* @__PURE__ */ jsx(
37452
38182
  Button,
37453
38183
  {
@@ -38379,6 +39109,8 @@ var init_GraphCanvas = __esm({
38379
39109
  selectedNodeId,
38380
39110
  repulsion = 800,
38381
39111
  linkDistance = 100,
39112
+ nodeSpacing = 28,
39113
+ linkOpacity = 0.18,
38382
39114
  layout = "force",
38383
39115
  entity,
38384
39116
  isLoading = false,
@@ -38538,6 +39270,25 @@ var init_GraphCanvas = __esm({
38538
39270
  node.x = Math.max(30, Math.min(w - 30, node.x));
38539
39271
  node.y = Math.max(30, Math.min(h - 30, node.y));
38540
39272
  }
39273
+ for (let i = 0; i < nodes.length; i++) {
39274
+ for (let j = i + 1; j < nodes.length; j++) {
39275
+ const a = nodes[i];
39276
+ const b = nodes[j];
39277
+ const dx = b.x - a.x;
39278
+ const dy = b.y - a.y;
39279
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
39280
+ const minDist = (a.size || 8) + (b.size || 8) + nodeSpacing;
39281
+ if (dist < minDist) {
39282
+ const push = (minDist - dist) / 2;
39283
+ const ux = dx / dist;
39284
+ const uy = dy / dist;
39285
+ a.x = Math.max(30, Math.min(w - 30, a.x - ux * push));
39286
+ a.y = Math.max(30, Math.min(h - 30, a.y - uy * push));
39287
+ b.x = Math.max(30, Math.min(w - 30, b.x + ux * push));
39288
+ b.y = Math.max(30, Math.min(h - 30, b.y + uy * push));
39289
+ }
39290
+ }
39291
+ }
38541
39292
  iterations++;
38542
39293
  forceUpdate((n) => n + 1);
38543
39294
  if (iterations < maxIterations) {
@@ -38551,7 +39302,7 @@ var init_GraphCanvas = __esm({
38551
39302
  return () => {
38552
39303
  cancelAnimationFrame(animRef.current);
38553
39304
  };
38554
- }, [propNodes, propEdges, layout, repulsion, linkDistance, logicalW, height]);
39305
+ }, [propNodes, propEdges, layout, repulsion, linkDistance, nodeSpacing, logicalW, height]);
38555
39306
  useEffect(() => {
38556
39307
  const canvas = canvasRef.current;
38557
39308
  if (!canvas) return;
@@ -38580,11 +39331,11 @@ var init_GraphCanvas = __esm({
38580
39331
  const target = nodes.find((n) => n.id === edge.target);
38581
39332
  if (!source || !target) continue;
38582
39333
  const incident = !!hoveredNode && (edge.source === hoveredNode || edge.target === hoveredNode);
38583
- ctx.globalAlpha = hoveredNode ? incident ? 1 : 0.12 : 1;
39334
+ ctx.globalAlpha = hoveredNode ? incident ? 1 : 0.05 : linkOpacity;
38584
39335
  ctx.beginPath();
38585
39336
  ctx.moveTo(source.x, source.y);
38586
39337
  ctx.lineTo(target.x, target.y);
38587
- ctx.strokeStyle = incident ? accentColor : edge.color || "#88888866";
39338
+ ctx.strokeStyle = incident ? accentColor : edge.color || "#888888";
38588
39339
  ctx.lineWidth = incident ? 2 : edge.weight ? Math.max(1, edge.weight) : 1;
38589
39340
  ctx.stroke();
38590
39341
  if (edge.label && showLabels) {
@@ -40198,7 +40949,7 @@ var init_DialogueBubble = __esm({
40198
40949
  }
40199
40950
  });
40200
40951
  function extractTitle(children) {
40201
- if (!React76__default.isValidElement(children)) return void 0;
40952
+ if (!React79__default.isValidElement(children)) return void 0;
40202
40953
  const props = children.props;
40203
40954
  if (typeof props.title === "string") {
40204
40955
  return props.title;
@@ -40243,7 +40994,7 @@ var init_DrawerSlot = __esm({
40243
40994
  }
40244
40995
  });
40245
40996
  function StateIndicator({
40246
- assetUrl = DEFAULT_ASSET_URL11,
40997
+ assetUrl = DEFAULT_ASSET_URL9,
40247
40998
  state = "idle",
40248
40999
  label,
40249
41000
  size = "md",
@@ -40282,13 +41033,13 @@ function StateIndicator({
40282
41033
  }
40283
41034
  );
40284
41035
  }
40285
- var DEFAULT_ASSET_URL11, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
41036
+ var DEFAULT_ASSET_URL9, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
40286
41037
  var init_StateIndicator = __esm({
40287
41038
  "components/game/atoms/StateIndicator.tsx"() {
40288
41039
  init_Box();
40289
41040
  init_Icon();
40290
41041
  init_cn();
40291
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
41042
+ DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
40292
41043
  DEFAULT_STATE_STYLES = {
40293
41044
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
40294
41045
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -40323,7 +41074,7 @@ function LinearView({
40323
41074
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
40324
41075
  const isDone = i < currentIdx;
40325
41076
  const isCurrent = i === currentIdx;
40326
- return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
41077
+ return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
40327
41078
  i > 0 && /* @__PURE__ */ jsx(
40328
41079
  Typography,
40329
41080
  {
@@ -41273,12 +42024,12 @@ var init_Form = __esm({
41273
42024
  const isSchemaEntity = isOrbitalEntitySchema(entity);
41274
42025
  const resolvedEntity = isSchemaEntity ? entity : void 0;
41275
42026
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
41276
- const normalizedInitialData = React76__default.useMemo(() => {
42027
+ const normalizedInitialData = React79__default.useMemo(() => {
41277
42028
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
41278
42029
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
41279
42030
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
41280
42031
  }, [entity, initialData]);
41281
- const entityDerivedFields = React76__default.useMemo(() => {
42032
+ const entityDerivedFields = React79__default.useMemo(() => {
41282
42033
  if (fields && fields.length > 0) return void 0;
41283
42034
  if (!resolvedEntity) return void 0;
41284
42035
  return resolvedEntity.fields.map(
@@ -41298,16 +42049,16 @@ var init_Form = __esm({
41298
42049
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
41299
42050
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
41300
42051
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
41301
- const [formData, setFormData] = React76__default.useState(
42052
+ const [formData, setFormData] = React79__default.useState(
41302
42053
  normalizedInitialData
41303
42054
  );
41304
- const [collapsedSections, setCollapsedSections] = React76__default.useState(
42055
+ const [collapsedSections, setCollapsedSections] = React79__default.useState(
41305
42056
  /* @__PURE__ */ new Set()
41306
42057
  );
41307
- const [submitError, setSubmitError] = React76__default.useState(null);
41308
- const formRef = React76__default.useRef(null);
42058
+ const [submitError, setSubmitError] = React79__default.useState(null);
42059
+ const formRef = React79__default.useRef(null);
41309
42060
  const formMode = props.mode;
41310
- const mountedRef = React76__default.useRef(false);
42061
+ const mountedRef = React79__default.useRef(false);
41311
42062
  if (!mountedRef.current) {
41312
42063
  mountedRef.current = true;
41313
42064
  debug("forms", "mount", {
@@ -41320,7 +42071,7 @@ var init_Form = __esm({
41320
42071
  });
41321
42072
  }
41322
42073
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
41323
- const evalContext = React76__default.useMemo(
42074
+ const evalContext = React79__default.useMemo(
41324
42075
  () => ({
41325
42076
  formValues: formData,
41326
42077
  globalVariables: externalContext?.globalVariables ?? {},
@@ -41329,7 +42080,7 @@ var init_Form = __esm({
41329
42080
  }),
41330
42081
  [formData, externalContext]
41331
42082
  );
41332
- React76__default.useEffect(() => {
42083
+ React79__default.useEffect(() => {
41333
42084
  debug("forms", "initialData-sync", {
41334
42085
  mode: formMode,
41335
42086
  normalizedInitialData,
@@ -41340,7 +42091,7 @@ var init_Form = __esm({
41340
42091
  setFormData(normalizedInitialData);
41341
42092
  }
41342
42093
  }, [normalizedInitialData]);
41343
- const processCalculations = React76__default.useCallback(
42094
+ const processCalculations = React79__default.useCallback(
41344
42095
  (changedFieldId, newFormData) => {
41345
42096
  if (!hiddenCalculations.length) return;
41346
42097
  const context = {
@@ -41365,7 +42116,7 @@ var init_Form = __esm({
41365
42116
  },
41366
42117
  [hiddenCalculations, externalContext, eventBus]
41367
42118
  );
41368
- const checkViolations = React76__default.useCallback(
42119
+ const checkViolations = React79__default.useCallback(
41369
42120
  (changedFieldId, newFormData) => {
41370
42121
  if (!violationTriggers.length) return;
41371
42122
  const context = {
@@ -41403,7 +42154,7 @@ var init_Form = __esm({
41403
42154
  processCalculations(name, newFormData);
41404
42155
  checkViolations(name, newFormData);
41405
42156
  };
41406
- const isFieldVisible = React76__default.useCallback(
42157
+ const isFieldVisible = React79__default.useCallback(
41407
42158
  (fieldName) => {
41408
42159
  const condition = conditionalFields[fieldName];
41409
42160
  if (!condition) return true;
@@ -41411,7 +42162,7 @@ var init_Form = __esm({
41411
42162
  },
41412
42163
  [conditionalFields, evalContext]
41413
42164
  );
41414
- const isSectionVisible = React76__default.useCallback(
42165
+ const isSectionVisible = React79__default.useCallback(
41415
42166
  (section) => {
41416
42167
  if (!section.condition) return true;
41417
42168
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -41487,7 +42238,7 @@ var init_Form = __esm({
41487
42238
  eventBus.emit(`UI:${onCancel}`);
41488
42239
  }
41489
42240
  };
41490
- const renderField = React76__default.useCallback(
42241
+ const renderField = React79__default.useCallback(
41491
42242
  (field) => {
41492
42243
  const fieldName = field.name || field.field;
41493
42244
  if (!fieldName) return null;
@@ -41508,7 +42259,7 @@ var init_Form = __esm({
41508
42259
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
41509
42260
  );
41510
42261
  const effectiveFields = entityDerivedFields ?? fields;
41511
- const normalizedFields = React76__default.useMemo(() => {
42262
+ const normalizedFields = React79__default.useMemo(() => {
41512
42263
  if (!effectiveFields || effectiveFields.length === 0) return [];
41513
42264
  return effectiveFields.map((field) => {
41514
42265
  if (typeof field === "string") {
@@ -41531,7 +42282,7 @@ var init_Form = __esm({
41531
42282
  return field;
41532
42283
  });
41533
42284
  }, [effectiveFields, resolvedEntity]);
41534
- const schemaFields = React76__default.useMemo(() => {
42285
+ const schemaFields = React79__default.useMemo(() => {
41535
42286
  if (normalizedFields.length === 0) return null;
41536
42287
  if (isDebugEnabled()) {
41537
42288
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -41541,7 +42292,7 @@ var init_Form = __esm({
41541
42292
  }
41542
42293
  return normalizedFields.map(renderField).filter(Boolean);
41543
42294
  }, [normalizedFields, renderField, entityName, conditionalFields]);
41544
- const sectionElements = React76__default.useMemo(() => {
42295
+ const sectionElements = React79__default.useMemo(() => {
41545
42296
  if (!sections || sections.length === 0) return null;
41546
42297
  return sections.map((section) => {
41547
42298
  if (!isSectionVisible(section)) {
@@ -42868,12 +43619,18 @@ function ModelLoader({
42868
43619
  });
42869
43620
  return cloned;
42870
43621
  }, [loadedModel, castShadow, receiveShadow]);
43622
+ const normFactor = useMemo(() => {
43623
+ if (!model) return 1;
43624
+ const box = new THREE3.Box3().setFromObject(model);
43625
+ const size = new THREE3.Vector3();
43626
+ box.getSize(size);
43627
+ const maxDim = Math.max(size.x, size.y, size.z);
43628
+ return maxDim > 0 && Number.isFinite(maxDim) ? 1 / maxDim : 1;
43629
+ }, [model]);
42871
43630
  const scaleArray = useMemo(() => {
42872
- if (typeof scale === "number") {
42873
- return [scale, scale, scale];
42874
- }
42875
- return scale;
42876
- }, [scale]);
43631
+ const base = typeof scale === "number" ? [scale, scale, scale] : scale;
43632
+ return [base[0] * normFactor, base[1] * normFactor, base[2] * normFactor];
43633
+ }, [scale, normFactor]);
42877
43634
  const rotationRad = useMemo(() => {
42878
43635
  return [
42879
43636
  rotation[0] * Math.PI / 180,
@@ -43084,6 +43841,29 @@ var init_GameCanvas3D2 = __esm({
43084
43841
  const controlsRef = useRef(null);
43085
43842
  const [hoveredTile, setHoveredTile] = useState(null);
43086
43843
  const [internalError, setInternalError] = useState(null);
43844
+ useEffect(() => {
43845
+ const el = containerRef.current;
43846
+ if (!el) return;
43847
+ let node = el;
43848
+ let depth = 0;
43849
+ while (node && depth < 8) {
43850
+ const cs = window.getComputedStyle(node);
43851
+ const rect = node.getBoundingClientRect();
43852
+ console.log("[almadar:ui:game:3d-height]", {
43853
+ depth,
43854
+ tag: node.tagName,
43855
+ id: node.id || void 0,
43856
+ className: node.className?.slice?.(0, 60) || void 0,
43857
+ rectHeight: rect.height,
43858
+ computedHeight: cs.height,
43859
+ computedMinHeight: cs.minHeight,
43860
+ computedFlex: cs.flex,
43861
+ computedOverflow: cs.overflow
43862
+ });
43863
+ node = node.parentElement;
43864
+ depth++;
43865
+ }
43866
+ }, []);
43087
43867
  const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
43088
43868
  const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
43089
43869
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
@@ -43473,7 +44253,7 @@ var init_GameCanvas3D2 = __esm({
43473
44253
  {
43474
44254
  ref: containerRef,
43475
44255
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
43476
- style: { minHeight: "85vh" },
44256
+ style: { height: "85vh" },
43477
44257
  "data-orientation": orientation,
43478
44258
  "data-camera-mode": cameraMode,
43479
44259
  "data-overlay": overlay,
@@ -43488,7 +44268,7 @@ var init_GameCanvas3D2 = __esm({
43488
44268
  near: 0.1,
43489
44269
  far: 1e3
43490
44270
  },
43491
- style: { background: backgroundColor, height: "85vh", width: "100%" },
44271
+ style: { background: backgroundColor, position: "absolute", inset: 0 },
43492
44272
  onClick: (e) => {
43493
44273
  if (e.target === e.currentTarget) {
43494
44274
  eventHandlers.handleCanvasClick(e);
@@ -44459,7 +45239,7 @@ var init_List = __esm({
44459
45239
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
44460
45240
  return [];
44461
45241
  }, [entity]);
44462
- const getItemActions = React76__default.useCallback(
45242
+ const getItemActions = React79__default.useCallback(
44463
45243
  (item) => {
44464
45244
  if (!itemActions) return [];
44465
45245
  if (typeof itemActions === "function") {
@@ -44935,7 +45715,7 @@ var init_MediaGallery = __esm({
44935
45715
  [selectable, selectedItems, selectionEvent, eventBus]
44936
45716
  );
44937
45717
  const entityData = Array.isArray(entity) ? entity : [];
44938
- const items = React76__default.useMemo(() => {
45718
+ const items = React79__default.useMemo(() => {
44939
45719
  if (propItems) return propItems;
44940
45720
  if (entityData.length === 0) return [];
44941
45721
  return entityData.map((record, idx) => ({
@@ -45105,9 +45885,9 @@ function MiniMap({
45105
45885
  viewportRect = DEFAULT_VIEWPORT,
45106
45886
  className
45107
45887
  }) {
45108
- const canvasRef = React76.useRef(null);
45109
- const frameRef = React76.useRef(0);
45110
- React76.useEffect(() => {
45888
+ const canvasRef = React79.useRef(null);
45889
+ const frameRef = React79.useRef(0);
45890
+ React79.useEffect(() => {
45111
45891
  const canvas = canvasRef.current;
45112
45892
  if (!canvas) return;
45113
45893
  const ctx = canvas.getContext("2d");
@@ -45204,7 +45984,7 @@ var init_MiniMap = __esm({
45204
45984
  }
45205
45985
  });
45206
45986
  function extractTitle2(children) {
45207
- if (!React76__default.isValidElement(children)) return void 0;
45987
+ if (!React79__default.isValidElement(children)) return void 0;
45208
45988
  const props = children.props;
45209
45989
  if (typeof props.title === "string") {
45210
45990
  return props.title;
@@ -45781,7 +46561,7 @@ var init_PricingPageTemplate = __esm({
45781
46561
  }
45782
46562
  });
45783
46563
  function ResourceCounter({
45784
- assetUrl = DEFAULT_ASSET_URL12,
46564
+ assetUrl = DEFAULT_ASSET_URL10,
45785
46565
  icon,
45786
46566
  label = "Gold",
45787
46567
  value = 250,
@@ -45824,7 +46604,7 @@ function ResourceCounter({
45824
46604
  }
45825
46605
  );
45826
46606
  }
45827
- var colorTokenClasses2, DEFAULT_ASSET_URL12, sizeMap15;
46607
+ var colorTokenClasses2, DEFAULT_ASSET_URL10, sizeMap15;
45828
46608
  var init_ResourceCounter = __esm({
45829
46609
  "components/game/atoms/ResourceCounter.tsx"() {
45830
46610
  init_cn();
@@ -45837,7 +46617,7 @@ var init_ResourceCounter = __esm({
45837
46617
  error: "text-error",
45838
46618
  muted: "text-muted-foreground"
45839
46619
  };
45840
- DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
46620
+ DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
45841
46621
  sizeMap15 = {
45842
46622
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
45843
46623
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -45846,31 +46626,33 @@ var init_ResourceCounter = __esm({
45846
46626
  ResourceCounter.displayName = "ResourceCounter";
45847
46627
  }
45848
46628
  });
45849
- function dungeonTerrain(x, y, stairsX, stairsY) {
46629
+ function resolveManifestUrl3(manifest, relative) {
46630
+ if (relative == null) return void 0;
46631
+ if (/^https?:\/\//.test(relative)) return relative;
46632
+ const base = manifest?.baseUrl;
46633
+ if (base == null) return relative;
46634
+ const cleanBase = base.replace(/\/$/, "");
46635
+ const cleanRel = relative.replace(/^\//, "");
46636
+ return `${cleanBase}/${cleanRel}`;
46637
+ }
46638
+ function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
45850
46639
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
45851
46640
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
45852
46641
  const isWall = isBorder || isPillar;
46642
+ const terrains = manifest?.terrains;
45853
46643
  if (x === stairsX && y === stairsY) {
45854
- return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
46644
+ return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
45855
46645
  }
45856
46646
  if (isWall) {
45857
- return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
45858
- }
45859
- const variant = (x * 3 + y * 7) % 5;
45860
- const sprites = [
45861
- `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
45862
- `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
45863
- `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
45864
- `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
45865
- `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
45866
- ];
45867
- return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
46647
+ return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
46648
+ }
46649
+ return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
45868
46650
  }
45869
- function buildDefaultDungeonTiles(stairsX, stairsY) {
46651
+ function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
45870
46652
  const tiles = [];
45871
46653
  for (let y = 0; y < DUNGEON_GRID_H; y++) {
45872
46654
  for (let x = 0; x < DUNGEON_GRID_W; x++) {
45873
- tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
46655
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY, manifest) });
45874
46656
  }
45875
46657
  }
45876
46658
  return tiles;
@@ -45900,20 +46682,48 @@ function RoguelikeBoard({
45900
46682
  className
45901
46683
  }) {
45902
46684
  const board = boardEntity(entity) ?? {};
45903
- const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
45904
- const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
45905
- const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
45906
- const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
45907
- const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
45908
- const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
46685
+ const assetManifest = propAssetManifest ?? board.assetManifest;
46686
+ const stairsX = propStairsX ?? num(board.stairsX, 14);
46687
+ const stairsY = propStairsY ?? num(board.stairsY, 14);
46688
+ const entityTiles = useMemo(
46689
+ () => rows(board.tiles).map((r) => ({
46690
+ x: num(r.x),
46691
+ y: num(r.y),
46692
+ terrain: r.terrain == null ? void 0 : str(r.terrain),
46693
+ terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
46694
+ passable: r.passable !== false
46695
+ })),
46696
+ [board.tiles]
46697
+ );
46698
+ const tiles = propTiles ?? (entityTiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? entityTiles : buildDefaultDungeonTiles(stairsX, stairsY, assetManifest));
46699
+ const entityEnemies = useMemo(
46700
+ () => rows(board.enemies).map((r) => ({
46701
+ id: str(r.id),
46702
+ x: num(r.x),
46703
+ y: num(r.y),
46704
+ hp: num(r.hp),
46705
+ attack: num(r.attack)
46706
+ })),
46707
+ [board.enemies]
46708
+ );
46709
+ const enemies = propEnemies ?? (entityEnemies.length > 0 ? entityEnemies : DEFAULT_ENEMIES);
46710
+ const entityItems = useMemo(
46711
+ () => rows(board.items).map((r) => ({
46712
+ id: str(r.id),
46713
+ x: num(r.x),
46714
+ y: num(r.y),
46715
+ kind: str(r.kind) || "health_potion"
46716
+ })),
46717
+ [board.items]
46718
+ );
46719
+ const items = propItems ?? (entityItems.length > 0 ? entityItems : DEFAULT_ITEMS);
46720
+ const player = propPlayer ?? (board.player == null ? { x: 1, y: 1 } : vec2(board.player));
45909
46721
  const playerHp = propPlayerHp ?? num(board.playerHp, 10);
45910
46722
  const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
45911
46723
  const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
45912
46724
  const depth = propDepth ?? num(board.depth, 1);
45913
46725
  const result = propResult ?? (str(board.result) || "none");
45914
46726
  const phase = propPhase ?? (str(board.phase) || "player_turn");
45915
- propStairsX ?? num(board.stairsX, 14);
45916
- propStairsY ?? num(board.stairsY, 14);
45917
46727
  const eventBus = useEventBus();
45918
46728
  const { t } = useTranslate();
45919
46729
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -45960,7 +46770,7 @@ function RoguelikeBoard({
45960
46770
  health: playerHp,
45961
46771
  maxHealth: playerMaxHp,
45962
46772
  unitType: "player",
45963
- sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
46773
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
45964
46774
  },
45965
46775
  ...liveEnemies.map((e) => ({
45966
46776
  id: e.id,
@@ -45970,19 +46780,19 @@ function RoguelikeBoard({
45970
46780
  health: e.hp,
45971
46781
  maxHealth: 6,
45972
46782
  unitType: "enemy",
45973
- sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
46783
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
45974
46784
  }))
45975
46785
  ];
45976
- }, [player, enemies, playerHp, playerMaxHp, t]);
46786
+ }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
45977
46787
  const isoFeatures = useMemo(
45978
46788
  () => items.map((it) => ({
45979
46789
  id: it.id,
45980
46790
  x: it.x,
45981
46791
  y: it.y,
45982
46792
  type: it.kind,
45983
- sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
46793
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
45984
46794
  })),
45985
- [items]
46795
+ [items, assetManifest]
45986
46796
  );
45987
46797
  const validMoves = useMemo(() => {
45988
46798
  if (result !== "none" || phase !== "player_turn") return [];
@@ -46041,8 +46851,8 @@ function RoguelikeBoard({
46041
46851
  onTileHover: (x, y) => setHoveredTile({ x, y }),
46042
46852
  onTileLeave: () => setHoveredTile(null),
46043
46853
  scale,
46044
- assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
46045
- assetManifest: propAssetManifest,
46854
+ assetBaseUrl: assetManifest?.baseUrl,
46855
+ assetManifest,
46046
46856
  unitScale,
46047
46857
  spriteHeightRatio,
46048
46858
  spriteMaxWidthRatio
@@ -46089,7 +46899,7 @@ function RoguelikeBoard({
46089
46899
  ] }) })
46090
46900
  ] });
46091
46901
  }
46092
- var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
46902
+ var DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS;
46093
46903
  var init_RoguelikeBoard = __esm({
46094
46904
  "components/game/organisms/RoguelikeBoard.tsx"() {
46095
46905
  "use client";
@@ -46101,10 +46911,8 @@ var init_RoguelikeBoard = __esm({
46101
46911
  init_Stack();
46102
46912
  init_IsometricCanvas();
46103
46913
  init_boardEntity();
46104
- CDN4 = "https://almadar-kflow-assets.web.app/shared";
46105
46914
  DUNGEON_GRID_W = 16;
46106
46915
  DUNGEON_GRID_H = 16;
46107
- buildDefaultDungeonTiles(14, 14);
46108
46916
  DEFAULT_ENEMIES = [
46109
46917
  { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
46110
46918
  { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
@@ -46116,11 +46924,6 @@ var init_RoguelikeBoard = __esm({
46116
46924
  { id: "i2", x: 7, y: 9, kind: "sword" },
46117
46925
  { id: "i3", x: 11, y: 5, kind: "shield" }
46118
46926
  ];
46119
- FEATURE_SPRITE = {
46120
- health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
46121
- sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
46122
- shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
46123
- };
46124
46927
  RoguelikeBoard.displayName = "RoguelikeBoard";
46125
46928
  }
46126
46929
  });
@@ -46158,40 +46961,40 @@ function RoguelikeTemplate({
46158
46961
  }
46159
46962
  );
46160
46963
  }
46161
- var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
46964
+ var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
46162
46965
  var init_RoguelikeTemplate = __esm({
46163
46966
  "components/game/templates/RoguelikeTemplate.tsx"() {
46164
46967
  init_RoguelikeBoard();
46165
- CDN5 = "https://almadar-kflow-assets.web.app/shared";
46968
+ CDN4 = "https://almadar-kflow-assets.web.app/shared";
46166
46969
  DEFAULT_ROGUELIKE_TILES = [
46167
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46168
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46169
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46170
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46171
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46172
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46173
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
46174
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
46175
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
46176
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46177
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46178
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
46179
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
46180
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
46181
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46182
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46183
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
46184
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
46185
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
46186
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46187
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46188
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46189
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46190
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
46191
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
46970
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46971
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46972
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46973
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46974
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46975
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46976
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
46977
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
46978
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
46979
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46980
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46981
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
46982
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
46983
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
46984
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46985
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46986
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
46987
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
46988
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
46989
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46990
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46991
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46992
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46993
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
46994
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
46192
46995
  ];
46193
46996
  DEFAULT_ROGUELIKE_MANIFEST = {
46194
- baseUrl: CDN5,
46997
+ baseUrl: CDN4,
46195
46998
  terrains: {
46196
46999
  floor: "/isometric-dungeon/Isometric/dirt_E.png",
46197
47000
  wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
@@ -46298,7 +47101,7 @@ var init_debugRegistry = __esm({
46298
47101
  }
46299
47102
  });
46300
47103
  function useDebugData() {
46301
- const [data, setData] = React76.useState(() => ({
47104
+ const [data, setData] = React79.useState(() => ({
46302
47105
  traits: [],
46303
47106
  ticks: [],
46304
47107
  guards: [],
@@ -46312,7 +47115,7 @@ function useDebugData() {
46312
47115
  },
46313
47116
  lastUpdate: Date.now()
46314
47117
  }));
46315
- React76.useEffect(() => {
47118
+ React79.useEffect(() => {
46316
47119
  const updateData = () => {
46317
47120
  setData({
46318
47121
  traits: getAllTraits(),
@@ -46421,12 +47224,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
46421
47224
  return positions;
46422
47225
  }
46423
47226
  function WalkMinimap() {
46424
- const [walkStep, setWalkStep] = React76.useState(null);
46425
- const [traits2, setTraits] = React76.useState([]);
46426
- const [coveredEdges, setCoveredEdges] = React76.useState([]);
46427
- const [completedTraits, setCompletedTraits] = React76.useState(/* @__PURE__ */ new Set());
46428
- const prevTraitRef = React76.useRef(null);
46429
- React76.useEffect(() => {
47227
+ const [walkStep, setWalkStep] = React79.useState(null);
47228
+ const [traits2, setTraits] = React79.useState([]);
47229
+ const [coveredEdges, setCoveredEdges] = React79.useState([]);
47230
+ const [completedTraits, setCompletedTraits] = React79.useState(/* @__PURE__ */ new Set());
47231
+ const prevTraitRef = React79.useRef(null);
47232
+ React79.useEffect(() => {
46430
47233
  const interval = setInterval(() => {
46431
47234
  const w = window;
46432
47235
  const step = w.__orbitalWalkStep;
@@ -46862,15 +47665,15 @@ var init_EntitiesTab = __esm({
46862
47665
  });
46863
47666
  function EventFlowTab({ events: events2 }) {
46864
47667
  const { t } = useTranslate();
46865
- const [filter, setFilter] = React76.useState("all");
46866
- const containerRef = React76.useRef(null);
46867
- const [autoScroll, setAutoScroll] = React76.useState(true);
46868
- React76.useEffect(() => {
47668
+ const [filter, setFilter] = React79.useState("all");
47669
+ const containerRef = React79.useRef(null);
47670
+ const [autoScroll, setAutoScroll] = React79.useState(true);
47671
+ React79.useEffect(() => {
46869
47672
  if (autoScroll && containerRef.current) {
46870
47673
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
46871
47674
  }
46872
47675
  }, [events2.length, autoScroll]);
46873
- const filteredEvents = React76.useMemo(() => {
47676
+ const filteredEvents = React79.useMemo(() => {
46874
47677
  if (filter === "all") return events2;
46875
47678
  return events2.filter((e) => e.type === filter);
46876
47679
  }, [events2, filter]);
@@ -46986,7 +47789,7 @@ var init_EventFlowTab = __esm({
46986
47789
  });
46987
47790
  function GuardsPanel({ guards }) {
46988
47791
  const { t } = useTranslate();
46989
- const [filter, setFilter] = React76.useState("all");
47792
+ const [filter, setFilter] = React79.useState("all");
46990
47793
  if (guards.length === 0) {
46991
47794
  return /* @__PURE__ */ jsx(
46992
47795
  EmptyState,
@@ -46999,7 +47802,7 @@ function GuardsPanel({ guards }) {
46999
47802
  }
47000
47803
  const passedCount = guards.filter((g) => g.result).length;
47001
47804
  const failedCount = guards.length - passedCount;
47002
- const filteredGuards = React76.useMemo(() => {
47805
+ const filteredGuards = React79.useMemo(() => {
47003
47806
  if (filter === "all") return guards;
47004
47807
  if (filter === "passed") return guards.filter((g) => g.result);
47005
47808
  return guards.filter((g) => !g.result);
@@ -47162,10 +47965,10 @@ function EffectBadge({ effect }) {
47162
47965
  }
47163
47966
  function TransitionTimeline({ transitions }) {
47164
47967
  const { t } = useTranslate();
47165
- const containerRef = React76.useRef(null);
47166
- const [autoScroll, setAutoScroll] = React76.useState(true);
47167
- const [expandedId, setExpandedId] = React76.useState(null);
47168
- React76.useEffect(() => {
47968
+ const containerRef = React79.useRef(null);
47969
+ const [autoScroll, setAutoScroll] = React79.useState(true);
47970
+ const [expandedId, setExpandedId] = React79.useState(null);
47971
+ React79.useEffect(() => {
47169
47972
  if (autoScroll && containerRef.current) {
47170
47973
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
47171
47974
  }
@@ -47445,9 +48248,9 @@ function getAllEvents(traits2) {
47445
48248
  function EventDispatcherTab({ traits: traits2, schema }) {
47446
48249
  const eventBus = useEventBus();
47447
48250
  const { t } = useTranslate();
47448
- const [log10, setLog] = React76.useState([]);
47449
- const prevStatesRef = React76.useRef(/* @__PURE__ */ new Map());
47450
- React76.useEffect(() => {
48251
+ const [log10, setLog] = React79.useState([]);
48252
+ const prevStatesRef = React79.useRef(/* @__PURE__ */ new Map());
48253
+ React79.useEffect(() => {
47451
48254
  for (const trait of traits2) {
47452
48255
  const prev = prevStatesRef.current.get(trait.id);
47453
48256
  if (prev && prev !== trait.currentState) {
@@ -47616,10 +48419,10 @@ function VerifyModePanel({
47616
48419
  localCount
47617
48420
  }) {
47618
48421
  const { t } = useTranslate();
47619
- const [expanded, setExpanded] = React76.useState(true);
47620
- const scrollRef = React76.useRef(null);
47621
- const prevCountRef = React76.useRef(0);
47622
- React76.useEffect(() => {
48422
+ const [expanded, setExpanded] = React79.useState(true);
48423
+ const scrollRef = React79.useRef(null);
48424
+ const prevCountRef = React79.useRef(0);
48425
+ React79.useEffect(() => {
47623
48426
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
47624
48427
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
47625
48428
  }
@@ -47676,10 +48479,10 @@ function RuntimeDebugger({
47676
48479
  schema
47677
48480
  }) {
47678
48481
  const { t } = useTranslate();
47679
- const [isCollapsed, setIsCollapsed] = React76.useState(mode === "verify" ? true : defaultCollapsed);
47680
- const [isVisible, setIsVisible] = React76.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
48482
+ const [isCollapsed, setIsCollapsed] = React79.useState(mode === "verify" ? true : defaultCollapsed);
48483
+ const [isVisible, setIsVisible] = React79.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
47681
48484
  const debugData = useDebugData();
47682
- React76.useEffect(() => {
48485
+ React79.useEffect(() => {
47683
48486
  if (mode === "inline") return;
47684
48487
  return onDebugToggle((enabled) => {
47685
48488
  setIsVisible(enabled);
@@ -47688,7 +48491,7 @@ function RuntimeDebugger({
47688
48491
  }
47689
48492
  });
47690
48493
  }, [mode]);
47691
- React76.useEffect(() => {
48494
+ React79.useEffect(() => {
47692
48495
  if (mode === "inline") return;
47693
48496
  const handleKeyDown = (e) => {
47694
48497
  if (e.key === "`" && isVisible) {
@@ -48248,7 +49051,7 @@ function SequenceBar({
48248
49051
  onSlotRemove(index);
48249
49052
  }, [onSlotRemove, playing]);
48250
49053
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
48251
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
49054
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
48252
49055
  i > 0 && /* @__PURE__ */ jsx(
48253
49056
  Typography,
48254
49057
  {
@@ -49244,7 +50047,7 @@ var init_StatCard = __esm({
49244
50047
  const labelToUse = propLabel ?? propTitle;
49245
50048
  const eventBus = useEventBus();
49246
50049
  const { t } = useTranslate();
49247
- const handleActionClick = React76__default.useCallback(() => {
50050
+ const handleActionClick = React79__default.useCallback(() => {
49248
50051
  if (action?.event) {
49249
50052
  eventBus.emit(`UI:${action.event}`, {});
49250
50053
  }
@@ -49255,7 +50058,7 @@ var init_StatCard = __esm({
49255
50058
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
49256
50059
  const isLoading = externalLoading ?? false;
49257
50060
  const error = externalError;
49258
- const computeMetricValue = React76__default.useCallback(
50061
+ const computeMetricValue = React79__default.useCallback(
49259
50062
  (metric, items) => {
49260
50063
  if (metric.value !== void 0) {
49261
50064
  return metric.value;
@@ -49294,7 +50097,7 @@ var init_StatCard = __esm({
49294
50097
  },
49295
50098
  []
49296
50099
  );
49297
- const schemaStats = React76__default.useMemo(() => {
50100
+ const schemaStats = React79__default.useMemo(() => {
49298
50101
  if (!metrics || metrics.length === 0) return null;
49299
50102
  return metrics.map((metric) => ({
49300
50103
  label: metric.label,
@@ -49302,7 +50105,7 @@ var init_StatCard = __esm({
49302
50105
  format: metric.format
49303
50106
  }));
49304
50107
  }, [metrics, data, computeMetricValue]);
49305
- const calculatedTrend = React76__default.useMemo(() => {
50108
+ const calculatedTrend = React79__default.useMemo(() => {
49306
50109
  if (manualTrend !== void 0) return manualTrend;
49307
50110
  if (previousValue === void 0 || currentValue2 === void 0)
49308
50111
  return void 0;
@@ -50003,7 +50806,7 @@ function formatDuration(seconds) {
50003
50806
  return `${Math.round(seconds)}s`;
50004
50807
  }
50005
50808
  function StatusEffect({
50006
- assetUrl = DEFAULT_ASSET_URL13,
50809
+ assetUrl = DEFAULT_ASSET_URL11,
50007
50810
  icon = "shield",
50008
50811
  label = "Shield",
50009
50812
  duration = 30,
@@ -50061,12 +50864,12 @@ function StatusEffect({
50061
50864
  label && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
50062
50865
  ] });
50063
50866
  }
50064
- var DEFAULT_ASSET_URL13, sizeMap16, variantStyles9;
50867
+ var DEFAULT_ASSET_URL11, sizeMap16, variantStyles9;
50065
50868
  var init_StatusEffect = __esm({
50066
50869
  "components/game/atoms/StatusEffect.tsx"() {
50067
50870
  init_cn();
50068
50871
  init_Icon();
50069
- DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
50872
+ DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
50070
50873
  sizeMap16 = {
50071
50874
  sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]", img: 20 },
50072
50875
  md: { container: "w-10 h-10", icon: "text-base", badge: "text-xs -top-1 -right-1 w-5 h-5", timer: "text-xs", img: 28 },
@@ -50352,7 +51155,7 @@ var init_Timeline = __esm({
50352
51155
  }) => {
50353
51156
  const { t } = useTranslate();
50354
51157
  const entityData = Array.isArray(entity) ? entity : [];
50355
- const items = React76__default.useMemo(() => {
51158
+ const items = React79__default.useMemo(() => {
50356
51159
  if (propItems) return propItems;
50357
51160
  if (entityData.length === 0) return [];
50358
51161
  return entityData.map((record, idx) => {
@@ -50509,7 +51312,7 @@ var init_TimerDisplay = __esm({
50509
51312
  }
50510
51313
  });
50511
51314
  function extractToastProps(children) {
50512
- if (!React76__default.isValidElement(children)) {
51315
+ if (!React79__default.isValidElement(children)) {
50513
51316
  if (typeof children === "string") {
50514
51317
  return { message: children };
50515
51318
  }
@@ -50547,7 +51350,7 @@ var init_ToastSlot = __esm({
50547
51350
  eventBus.emit("UI:CLOSE");
50548
51351
  };
50549
51352
  if (!isVisible) return null;
50550
- const isCustomContent = React76__default.isValidElement(children) && !message;
51353
+ const isCustomContent = React79__default.isValidElement(children) && !message;
50551
51354
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
50552
51355
  Toast,
50553
51356
  {
@@ -50563,82 +51366,442 @@ var init_ToastSlot = __esm({
50563
51366
  ToastSlot.displayName = "ToastSlot";
50564
51367
  }
50565
51368
  });
51369
+ function resolveManifestUrl4(manifest, relative) {
51370
+ if (relative == null || relative === "") return void 0;
51371
+ if (/^https?:\/\//.test(relative)) return relative;
51372
+ const base = manifest?.baseUrl;
51373
+ if (base == null) return relative;
51374
+ const cleanBase = base.replace(/\/$/, "");
51375
+ const cleanRel = relative.replace(/^\//, "");
51376
+ return `${cleanBase}/${cleanRel}`;
51377
+ }
51378
+ function readPlayer(v) {
51379
+ if (v == null || typeof v !== "object") return void 0;
51380
+ const o = v;
51381
+ return { x: num(o.x), y: num(o.y) };
51382
+ }
51383
+ function TopDownShooterBoard({
51384
+ entity,
51385
+ player: propPlayer,
51386
+ enemies: propEnemies,
51387
+ projectiles: propProjectiles,
51388
+ score: propScore,
51389
+ wave: propWave,
51390
+ lives: propLives,
51391
+ result: propResult,
51392
+ assetManifest: propAssetManifest,
51393
+ width = DEFAULT_WIDTH,
51394
+ height = DEFAULT_HEIGHT,
51395
+ spriteSize = 32,
51396
+ moveEvent = "MOVE",
51397
+ fireEvent = "FIRE",
51398
+ playAgainEvent = "PLAY_AGAIN",
51399
+ gameEndEvent = "GAME_END",
51400
+ className
51401
+ }) {
51402
+ const board = boardEntity(entity) ?? {};
51403
+ const eventBus = useEventBus();
51404
+ const { t } = useTranslate();
51405
+ const assetManifest = propAssetManifest ?? board.assetManifest;
51406
+ const player = propPlayer ?? readPlayer(board.player) ?? { x: width / 2, y: height - spriteSize };
51407
+ const enemies = useMemo(
51408
+ () => propEnemies ?? rows(board.enemies).map((r) => ({
51409
+ id: str(r.id),
51410
+ x: num(r.x),
51411
+ y: num(r.y),
51412
+ hp: num(r.hp, 1)
51413
+ })),
51414
+ [propEnemies, board.enemies]
51415
+ );
51416
+ const projectiles = useMemo(
51417
+ () => propProjectiles ?? rows(board.projectiles).map((r) => ({
51418
+ id: str(r.id),
51419
+ x: num(r.x),
51420
+ y: num(r.y),
51421
+ vx: num(r.vx),
51422
+ vy: num(r.vy)
51423
+ })),
51424
+ [propProjectiles, board.projectiles]
51425
+ );
51426
+ const score = propScore ?? num(board.score, 0);
51427
+ const wave = propWave ?? num(board.wave, 1);
51428
+ const lives = propLives ?? num(board.lives, 3);
51429
+ const result = propResult ?? (str(board.result) || "none");
51430
+ const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
51431
+ const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
51432
+ const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
51433
+ const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
51434
+ const spriteUrls = useMemo(
51435
+ () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
51436
+ [playerSprite, enemySprite, projectileSprite]
51437
+ );
51438
+ const { getImage } = useImageCache(spriteUrls);
51439
+ const sceneRef = useRef({ player, enemies, projectiles, playerSprite, enemySprite, projectileSprite });
51440
+ sceneRef.current = { player, enemies, projectiles, playerSprite, enemySprite, projectileSprite };
51441
+ boardLog2.debug("shooter-resolve", {
51442
+ player: { x: player.x, y: player.y },
51443
+ enemyCount: enemies.length,
51444
+ projectileCount: projectiles.length,
51445
+ wave,
51446
+ lives,
51447
+ result,
51448
+ hasPlayerSprite: playerSprite != null
51449
+ });
51450
+ const onDraw = useCallback(
51451
+ (ctx, _frame) => {
51452
+ const scene = sceneRef.current;
51453
+ ctx.fillStyle = "#10141c";
51454
+ ctx.fillRect(0, 0, width, height);
51455
+ const half = spriteSize / 2;
51456
+ for (const p2 of scene.projectiles) {
51457
+ const img = scene.projectileSprite ? getImage(scene.projectileSprite) : void 0;
51458
+ if (img) {
51459
+ ctx.drawImage(img, p2.x - half / 2, p2.y - half / 2, spriteSize / 2, spriteSize / 2);
51460
+ } else {
51461
+ ctx.fillStyle = "#ffd34d";
51462
+ ctx.beginPath();
51463
+ ctx.arc(p2.x, p2.y, spriteSize / 6, 0, Math.PI * 2);
51464
+ ctx.fill();
51465
+ }
51466
+ }
51467
+ for (const e of scene.enemies) {
51468
+ const img = scene.enemySprite ? getImage(scene.enemySprite) : void 0;
51469
+ if (img) {
51470
+ ctx.drawImage(img, e.x - half, e.y - half, spriteSize, spriteSize);
51471
+ } else {
51472
+ ctx.fillStyle = "#e0524d";
51473
+ ctx.fillRect(e.x - half, e.y - half, spriteSize, spriteSize);
51474
+ }
51475
+ }
51476
+ const pImg = scene.playerSprite ? getImage(scene.playerSprite) : void 0;
51477
+ if (pImg) {
51478
+ ctx.drawImage(pImg, scene.player.x - half, scene.player.y - half, spriteSize, spriteSize);
51479
+ } else {
51480
+ ctx.fillStyle = "#4da3ff";
51481
+ ctx.beginPath();
51482
+ ctx.moveTo(scene.player.x, scene.player.y - half);
51483
+ ctx.lineTo(scene.player.x + half, scene.player.y + half);
51484
+ ctx.lineTo(scene.player.x - half, scene.player.y + half);
51485
+ ctx.closePath();
51486
+ ctx.fill();
51487
+ }
51488
+ },
51489
+ [getImage, width, height, spriteSize]
51490
+ );
51491
+ const moveEventRef = useRef(moveEvent);
51492
+ moveEventRef.current = moveEvent;
51493
+ const fireEventRef = useRef(fireEvent);
51494
+ fireEventRef.current = fireEvent;
51495
+ const resultRef = useRef(result);
51496
+ resultRef.current = result;
51497
+ const playerRef = useRef(player);
51498
+ playerRef.current = player;
51499
+ useEffect(() => {
51500
+ function onKeyDown(e) {
51501
+ if (resultRef.current !== "none") return;
51502
+ let dx = 0;
51503
+ let dy = 0;
51504
+ switch (e.key) {
51505
+ case "ArrowUp":
51506
+ case "w":
51507
+ dy = -1;
51508
+ break;
51509
+ case "ArrowDown":
51510
+ case "s":
51511
+ dy = 1;
51512
+ break;
51513
+ case "ArrowLeft":
51514
+ case "a":
51515
+ dx = -1;
51516
+ break;
51517
+ case "ArrowRight":
51518
+ case "d":
51519
+ dx = 1;
51520
+ break;
51521
+ case " ": {
51522
+ e.preventDefault();
51523
+ const evt = fireEventRef.current;
51524
+ if (evt) {
51525
+ eventBus.emit(`UI:${evt}`, { tx: playerRef.current.x, ty: 0 });
51526
+ }
51527
+ return;
51528
+ }
51529
+ default:
51530
+ return;
51531
+ }
51532
+ e.preventDefault();
51533
+ const moveEvt = moveEventRef.current;
51534
+ if (moveEvt) {
51535
+ eventBus.emit(`UI:${moveEvt}`, { dx, dy });
51536
+ }
51537
+ }
51538
+ window.addEventListener("keydown", onKeyDown);
51539
+ return () => window.removeEventListener("keydown", onKeyDown);
51540
+ }, [eventBus]);
51541
+ const handleFireClick = useCallback(
51542
+ (e) => {
51543
+ if (result !== "none") return;
51544
+ const evt = fireEventRef.current;
51545
+ if (!evt) return;
51546
+ const rect = e.currentTarget.getBoundingClientRect();
51547
+ const tx = e.clientX - rect.left;
51548
+ const ty = e.clientY - rect.top;
51549
+ eventBus.emit(`UI:${evt}`, { tx, ty });
51550
+ },
51551
+ [result, eventBus]
51552
+ );
51553
+ const handlePlayAgain = useCallback(() => {
51554
+ if (playAgainEvent) {
51555
+ eventBus.emit(`UI:${playAgainEvent}`, {});
51556
+ }
51557
+ }, [playAgainEvent, eventBus]);
51558
+ const gameEndEmittedRef = useRef(false);
51559
+ useEffect(() => {
51560
+ if ((result === "won" || result === "lost") && gameEndEvent) {
51561
+ if (!gameEndEmittedRef.current) {
51562
+ gameEndEmittedRef.current = true;
51563
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
51564
+ }
51565
+ } else {
51566
+ gameEndEmittedRef.current = false;
51567
+ }
51568
+ }, [result, gameEndEvent, eventBus]);
51569
+ const isGameOver = result === "won" || result === "lost";
51570
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("top-down-shooter-board relative bg-background", className), gap: "none", children: [
51571
+ /* @__PURE__ */ jsxs(HStack, { className: "px-4 py-2 border-b border-border bg-surface", gap: "lg", align: "center", children: [
51572
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
51573
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.score") ?? "Score" }),
51574
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: score })
51575
+ ] }),
51576
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
51577
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.wave") ?? "Wave" }),
51578
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: wave })
51579
+ ] }),
51580
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
51581
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.lives") ?? "Lives" }),
51582
+ /* @__PURE__ */ jsx(
51583
+ Typography,
51584
+ {
51585
+ variant: "body2",
51586
+ weight: "bold",
51587
+ className: lives <= 1 ? "text-error" : "text-success",
51588
+ children: lives
51589
+ }
51590
+ )
51591
+ ] })
51592
+ ] }),
51593
+ /* @__PURE__ */ jsxs(Box, { className: "relative", onClick: handleFireClick, children: [
51594
+ /* @__PURE__ */ jsx(
51595
+ GameCanvas2D,
51596
+ {
51597
+ width,
51598
+ height,
51599
+ backgroundImage: backgroundSprite,
51600
+ assetBaseUrl: assetManifest?.baseUrl,
51601
+ onDraw
51602
+ }
51603
+ ),
51604
+ isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
51605
+ /* @__PURE__ */ jsx(
51606
+ Typography,
51607
+ {
51608
+ variant: "h2",
51609
+ className: cn(
51610
+ "text-4xl font-black tracking-widest uppercase",
51611
+ result === "won" ? "text-warning" : "text-error"
51612
+ ),
51613
+ children: result === "won" ? t("shooter.victory") ?? "Victory!" : t("shooter.defeat") ?? "Defeat!"
51614
+ }
51615
+ ),
51616
+ /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("shooter.cleared") ?? `Cleared wave ${wave} \u2014 score ${score}` : t("shooter.overrun") ?? "You were overrun." }),
51617
+ /* @__PURE__ */ jsx(
51618
+ Button,
51619
+ {
51620
+ variant: "primary",
51621
+ className: "px-8 py-3 font-semibold",
51622
+ onClick: handlePlayAgain,
51623
+ children: t("shooter.playAgain") ?? "Play Again"
51624
+ }
51625
+ )
51626
+ ] }) })
51627
+ ] })
51628
+ ] });
51629
+ }
51630
+ var boardLog2, DEFAULT_WIDTH, DEFAULT_HEIGHT;
51631
+ var init_TopDownShooterBoard = __esm({
51632
+ "components/game/organisms/TopDownShooterBoard.tsx"() {
51633
+ "use client";
51634
+ init_cn();
51635
+ init_useEventBus();
51636
+ init_Box();
51637
+ init_Button();
51638
+ init_Typography();
51639
+ init_Stack();
51640
+ init_GameCanvas2D();
51641
+ init_useImageCache();
51642
+ init_boardEntity();
51643
+ boardLog2 = createLogger("almadar:ui:game:top-down-shooter-board");
51644
+ DEFAULT_WIDTH = 640;
51645
+ DEFAULT_HEIGHT = 480;
51646
+ TopDownShooterBoard.displayName = "TopDownShooterBoard";
51647
+ }
51648
+ });
51649
+ function isEntityRow3(value) {
51650
+ return value != null && typeof value === "object" && !Array.isArray(value);
51651
+ }
51652
+ function TopDownShooterTemplate({
51653
+ entity,
51654
+ title = "Arena Shooter",
51655
+ player,
51656
+ enemies,
51657
+ projectiles,
51658
+ score,
51659
+ wave,
51660
+ lives,
51661
+ result,
51662
+ assetManifest,
51663
+ width,
51664
+ height,
51665
+ spriteSize,
51666
+ moveEvent,
51667
+ fireEvent,
51668
+ playAgainEvent,
51669
+ gameEndEvent,
51670
+ className
51671
+ }) {
51672
+ const resolved = isEntityRow3(entity) ? entity : void 0;
51673
+ return /* @__PURE__ */ jsxs(
51674
+ Box,
51675
+ {
51676
+ display: "flex",
51677
+ fullHeight: true,
51678
+ className: cn("top-down-shooter-template flex-col", className),
51679
+ children: [
51680
+ /* @__PURE__ */ jsx(
51681
+ HStack,
51682
+ {
51683
+ gap: "sm",
51684
+ align: "center",
51685
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
51686
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
51687
+ }
51688
+ ),
51689
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
51690
+ TopDownShooterBoard,
51691
+ {
51692
+ entity: resolved,
51693
+ player,
51694
+ enemies,
51695
+ projectiles,
51696
+ score,
51697
+ wave,
51698
+ lives,
51699
+ result,
51700
+ assetManifest,
51701
+ width,
51702
+ height,
51703
+ spriteSize,
51704
+ moveEvent,
51705
+ fireEvent,
51706
+ playAgainEvent,
51707
+ gameEndEvent,
51708
+ className: "h-full"
51709
+ }
51710
+ ) })
51711
+ ]
51712
+ }
51713
+ );
51714
+ }
51715
+ var init_TopDownShooterTemplate = __esm({
51716
+ "components/game/templates/TopDownShooterTemplate.tsx"() {
51717
+ init_cn();
51718
+ init_Box();
51719
+ init_Stack();
51720
+ init_Typography();
51721
+ init_TopDownShooterBoard();
51722
+ TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
51723
+ }
51724
+ });
51725
+ function resolveManifestUrl5(manifest, relative) {
51726
+ if (relative == null) return void 0;
51727
+ if (/^https?:\/\//.test(relative)) return relative;
51728
+ const base = manifest?.baseUrl;
51729
+ if (base == null) return relative;
51730
+ const cleanBase = base.replace(/\/$/, "");
51731
+ const cleanRel = relative.replace(/^\//, "");
51732
+ return `${cleanBase}/${cleanRel}`;
51733
+ }
50566
51734
  function buildDefaultTDTiles() {
50567
51735
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
50568
51736
  const tiles = [];
50569
51737
  for (let y = 0; y < TD_GRID_H; y++) {
50570
51738
  for (let x = 0; x < TD_GRID_W; x++) {
50571
51739
  if (pathSet.has(`${x},${y}`)) {
50572
- tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
51740
+ tiles.push({ x, y, terrain: "path", passable: false });
50573
51741
  } else {
50574
51742
  const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
50575
- const terrainKey = ["ground", "grass", "dirt"][variant];
50576
- tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
51743
+ const terrainKey = ["ground", "grass", "stone"][variant];
51744
+ tiles.push({ x, y, terrain: terrainKey, passable: true });
50577
51745
  }
50578
51746
  }
50579
51747
  }
50580
51748
  return tiles;
50581
51749
  }
50582
- function tilesToIso(tiles) {
50583
- return tiles.map((t) => ({
50584
- x: t.x,
50585
- y: t.y,
50586
- terrain: t.terrain,
50587
- terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
50588
- passable: t.passable
50589
- }));
50590
- }
50591
- function towersToUnits(towers) {
50592
- return towers.map((t) => ({
50593
- id: t.id,
50594
- position: { x: t.x, y: t.y },
50595
- name: "Tower",
50596
- team: "player",
50597
- sprite: TOWER_SPRITE,
50598
- unitType: "guardian",
50599
- health: 1,
50600
- maxHealth: 1
50601
- }));
51750
+ function tilesToIso2(tiles, manifest) {
51751
+ return tiles.map((t) => {
51752
+ const key = t.terrain ?? "ground";
51753
+ const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
51754
+ return {
51755
+ x: t.x,
51756
+ y: t.y,
51757
+ terrain: t.terrain,
51758
+ terrainSprite: sprite,
51759
+ passable: t.passable
51760
+ };
51761
+ });
50602
51762
  }
50603
- function creepsToUnits(creeps) {
51763
+ function creepsToUnits(creeps, manifest) {
51764
+ const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
50604
51765
  return creeps.map((c) => ({
50605
51766
  id: c.id,
50606
51767
  position: { x: c.x, y: c.y },
50607
51768
  name: "Creep",
50608
51769
  team: "enemy",
50609
- sprite: CREEP_SPRITE,
50610
- unitType: "scrapper",
51770
+ sprite,
51771
+ unitType: "creep",
50611
51772
  health: c.hp,
50612
51773
  maxHealth: c.maxHp
50613
51774
  }));
50614
51775
  }
50615
- function pathToFeatures(path) {
50616
- return path.map((p2, i) => ({
50617
- id: `path-${i}`,
50618
- x: p2.x,
50619
- y: p2.y,
50620
- type: "path-marker",
50621
- sprite: `${CDN6}world-map/road_straight.png`
50622
- }));
50623
- }
50624
- function heroToUnit(hero) {
51776
+ function heroToUnit(hero, manifest) {
50625
51777
  return {
50626
51778
  id: hero.id,
50627
51779
  position: { x: hero.x, y: hero.y },
50628
51780
  name: "Hero",
50629
51781
  team: "player",
50630
- sprite: HERO_SPRITE,
50631
- unitType: "amir",
51782
+ sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
51783
+ unitType: "hero",
50632
51784
  health: 1,
50633
51785
  maxHealth: 1
50634
51786
  };
50635
51787
  }
51788
+ function towersToFeatures(towers, manifest) {
51789
+ const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
51790
+ return towers.map((t) => ({
51791
+ id: t.id,
51792
+ x: t.x,
51793
+ y: t.y,
51794
+ type: "tower",
51795
+ sprite
51796
+ }));
51797
+ }
50636
51798
  function TowerDefenseBoard({
50637
51799
  entity,
50638
51800
  tiles: propTiles,
50639
51801
  path: propPath,
50640
51802
  towers: propTowers,
50641
51803
  creeps: propCreeps,
51804
+ assetManifest: propAssetManifest,
50642
51805
  hero: propHero,
50643
51806
  gold: propGold,
50644
51807
  lives: propLives,
@@ -50661,12 +51824,51 @@ function TowerDefenseBoard({
50661
51824
  const board = boardEntity(entity) ?? {};
50662
51825
  const eventBus = useEventBus();
50663
51826
  const { t } = useTranslate();
50664
- const rawTiles = propTiles ?? rows(board.tiles);
51827
+ const assetManifest = propAssetManifest ?? board.assetManifest;
51828
+ const entityTiles = useMemo(
51829
+ () => rows(board.tiles).map((r) => ({
51830
+ x: num(r.x),
51831
+ y: num(r.y),
51832
+ terrain: r.terrain == null ? void 0 : str(r.terrain),
51833
+ terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
51834
+ passable: r.passable !== false
51835
+ })),
51836
+ [board.tiles]
51837
+ );
51838
+ const rawTiles = propTiles ?? entityTiles;
50665
51839
  const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
50666
- const rawPath = propPath ?? rows(board.path);
51840
+ const entityPath = useMemo(
51841
+ () => rows(board.path).map((r) => ({ x: num(r.x), y: num(r.y) })),
51842
+ [board.path]
51843
+ );
51844
+ const rawPath = propPath ?? entityPath;
50667
51845
  const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
50668
- const towers = propTowers ?? rows(board.towers);
50669
- const creeps = propCreeps ?? rows(board.creeps);
51846
+ const entityTowers = useMemo(
51847
+ () => rows(board.towers).map((r) => ({
51848
+ id: str(r.id),
51849
+ x: num(r.x),
51850
+ y: num(r.y),
51851
+ range: num(r.range),
51852
+ damage: num(r.damage),
51853
+ cooldown: num(r.cooldown),
51854
+ lastFiredAt: r.lastFiredAt == null ? void 0 : num(r.lastFiredAt)
51855
+ })),
51856
+ [board.towers]
51857
+ );
51858
+ const towers = propTowers ?? entityTowers;
51859
+ const entityCreeps = useMemo(
51860
+ () => rows(board.creeps).map((r) => ({
51861
+ id: str(r.id),
51862
+ x: num(r.x),
51863
+ y: num(r.y),
51864
+ hp: num(r.hp),
51865
+ maxHp: num(r.maxHp),
51866
+ pathIndex: num(r.pathIndex),
51867
+ speed: num(r.speed)
51868
+ })),
51869
+ [board.creeps]
51870
+ );
51871
+ const creeps = propCreeps ?? entityCreeps;
50670
51872
  const hero = propHero ?? { id: "hero", x: 8, y: 8 };
50671
51873
  const gold = propGold ?? num(board.gold, 100);
50672
51874
  const lives = propLives ?? num(board.lives, 20);
@@ -50718,12 +51920,11 @@ function TowerDefenseBoard({
50718
51920
  (t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
50719
51921
  ).map((t2) => ({ x: t2.x, y: t2.y }));
50720
51922
  }, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
50721
- const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
50722
- const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
50723
- const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
50724
- const heroUnit = useMemo(() => heroToUnit(hero), [hero]);
50725
- const isoUnits = useMemo(() => [...towerUnits, ...creepUnits, heroUnit], [towerUnits, creepUnits, heroUnit]);
50726
- const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
51923
+ const isoTiles = useMemo(() => tilesToIso2(tiles, assetManifest), [tiles, assetManifest]);
51924
+ const creepUnits = useMemo(() => creepsToUnits(creeps, assetManifest), [creeps, assetManifest]);
51925
+ const heroUnit = useMemo(() => heroToUnit(hero, assetManifest), [hero, assetManifest]);
51926
+ const isoUnits = useMemo(() => [...creepUnits, heroUnit], [creepUnits, heroUnit]);
51927
+ const towerFeatures = useMemo(() => towersToFeatures(towers, assetManifest), [towers, assetManifest]);
50727
51928
  const handleTileClick = useCallback((x, y) => {
50728
51929
  if (result !== "none") return;
50729
51930
  if (pathPositions.has(`${x},${y}`)) return;
@@ -50782,7 +51983,9 @@ function TowerDefenseBoard({
50782
51983
  {
50783
51984
  tiles: isoTiles,
50784
51985
  units: isoUnits,
50785
- features: pathFeatures,
51986
+ features: towerFeatures,
51987
+ assetBaseUrl: assetManifest?.baseUrl,
51988
+ assetManifest,
50786
51989
  validMoves,
50787
51990
  hoveredTile,
50788
51991
  onTileClick: handleTileClick,
@@ -50821,7 +52024,7 @@ function TowerDefenseBoard({
50821
52024
  ] }) })
50822
52025
  ] });
50823
52026
  }
50824
- var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE, HERO_SPRITE;
52027
+ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
50825
52028
  var init_TowerDefenseBoard = __esm({
50826
52029
  "components/game/organisms/TowerDefenseBoard.tsx"() {
50827
52030
  "use client";
@@ -50833,16 +52036,8 @@ var init_TowerDefenseBoard = __esm({
50833
52036
  init_Stack();
50834
52037
  init_IsometricCanvas();
50835
52038
  init_boardEntity();
50836
- CDN6 = "https://almadar-kflow-assets.web.app/shared/";
50837
52039
  TD_GRID_W = 16;
50838
52040
  TD_GRID_H = 16;
50839
- TERRAIN_SPRITES = {
50840
- ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
50841
- path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
50842
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
50843
- grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
50844
- dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
50845
- };
50846
52041
  DEFAULT_TD_PATH = [
50847
52042
  { x: 2, y: 0 },
50848
52043
  { x: 2, y: 1 },
@@ -50895,9 +52090,6 @@ var init_TowerDefenseBoard = __esm({
50895
52090
  { x: 13, y: 15 }
50896
52091
  ];
50897
52092
  DEFAULT_TD_TILES = buildDefaultTDTiles();
50898
- TOWER_SPRITE = `${CDN6}sprite-sheets/guardian-sprite-sheet-se.png`;
50899
- CREEP_SPRITE = `${CDN6}sprite-sheets/scrapper-sprite-sheet-se.png`;
50900
- HERO_SPRITE = `${CDN6}sprite-sheets/amir-sprite-sheet-se.png`;
50901
52093
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
50902
52094
  }
50903
52095
  });
@@ -51165,6 +52357,214 @@ var init_UncontrolledBattleBoard = __esm({
51165
52357
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
51166
52358
  }
51167
52359
  });
52360
+ function resolveManifestUrl6(manifest, relative) {
52361
+ if (relative == null) return void 0;
52362
+ if (/^https?:\/\//.test(relative)) return relative;
52363
+ const base = manifest?.baseUrl;
52364
+ if (base == null) return relative;
52365
+ const cleanBase = base.replace(/\/$/, "");
52366
+ const cleanRel = relative.replace(/^\//, "");
52367
+ return `${cleanBase}/${cleanRel}`;
52368
+ }
52369
+ function VisualNovelBoard({
52370
+ entity,
52371
+ nodes: propNodes,
52372
+ currentNodeId: propCurrentNodeId,
52373
+ assetManifest: propAssetManifest,
52374
+ typewriterSpeed = 30,
52375
+ portraitScale = 1,
52376
+ chooseEvent,
52377
+ advanceEvent,
52378
+ restartEvent,
52379
+ className
52380
+ }) {
52381
+ const board = boardEntity(entity) ?? {};
52382
+ const eventBus = useEventBus();
52383
+ const assetManifest = propAssetManifest ?? board.assetManifest;
52384
+ const entityNodes = useMemo(
52385
+ () => rows(board.nodes).map((r) => ({
52386
+ id: str(r.id),
52387
+ speaker: str(r.speaker),
52388
+ text: str(r.text),
52389
+ backgroundKey: r.backgroundKey == null ? void 0 : str(r.backgroundKey),
52390
+ portraitKey: r.portraitKey == null ? void 0 : str(r.portraitKey),
52391
+ choices: rows(r.choices).map((c) => ({
52392
+ label: str(c.label),
52393
+ nextId: str(c.nextId)
52394
+ }))
52395
+ })),
52396
+ [board.nodes]
52397
+ );
52398
+ const rawNodes = propNodes ?? entityNodes;
52399
+ const nodes = rawNodes.length > 0 ? rawNodes : DEFAULT_NODES;
52400
+ const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
52401
+ const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
52402
+ const backgroundImage = useMemo(
52403
+ () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
52404
+ [assetManifest, currentNode?.backgroundKey]
52405
+ );
52406
+ const portraitUrl = useMemo(
52407
+ () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
52408
+ [assetManifest, currentNode?.portraitKey]
52409
+ );
52410
+ const dialogueChoices = useMemo(
52411
+ () => (currentNode?.choices ?? []).map((c) => ({ text: c.label, next: c.nextId })),
52412
+ [currentNode?.choices]
52413
+ );
52414
+ const handleChoice = useCallback(
52415
+ (choice) => {
52416
+ const index = dialogueChoices.findIndex((c) => c.next === choice.next && c.text === choice.text);
52417
+ if (chooseEvent) {
52418
+ eventBus.emit(`UI:${chooseEvent}`, { choiceIndex: index });
52419
+ }
52420
+ },
52421
+ [dialogueChoices, chooseEvent, eventBus]
52422
+ );
52423
+ const handleAdvance = useCallback(() => {
52424
+ if (advanceEvent) {
52425
+ eventBus.emit(`UI:${advanceEvent}`, {});
52426
+ }
52427
+ }, [advanceEvent, eventBus]);
52428
+ const handleRestart = useCallback(() => {
52429
+ if (restartEvent) {
52430
+ eventBus.emit(`UI:${restartEvent}`, {});
52431
+ }
52432
+ }, [restartEvent, eventBus]);
52433
+ if (!currentNode) {
52434
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("visual-novel-board relative min-h-[600px] bg-background items-center justify-center", className), gap: "lg", children: [
52435
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", color: "muted", children: "No dialogue nodes" }),
52436
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleRestart, children: "Restart" })
52437
+ ] });
52438
+ }
52439
+ return /* @__PURE__ */ jsx(Box, { className: cn("visual-novel-board relative min-h-[600px] bg-background overflow-hidden", className), children: /* @__PURE__ */ jsx(
52440
+ DialogueBox,
52441
+ {
52442
+ dialogue: {
52443
+ speaker: currentNode.speaker,
52444
+ text: currentNode.text,
52445
+ choices: dialogueChoices
52446
+ },
52447
+ typewriterSpeed,
52448
+ position: "bottom",
52449
+ backgroundImage,
52450
+ portraitUrl,
52451
+ portraitScale,
52452
+ onChoice: handleChoice,
52453
+ onAdvance: handleAdvance
52454
+ }
52455
+ ) });
52456
+ }
52457
+ var DEFAULT_NODES;
52458
+ var init_VisualNovelBoard = __esm({
52459
+ "components/game/organisms/VisualNovelBoard.tsx"() {
52460
+ "use client";
52461
+ init_cn();
52462
+ init_useEventBus();
52463
+ init_Box();
52464
+ init_Typography();
52465
+ init_Stack();
52466
+ init_Button();
52467
+ init_DialogueBox();
52468
+ init_boardEntity();
52469
+ DEFAULT_NODES = [
52470
+ {
52471
+ id: "start",
52472
+ speaker: "Narrator",
52473
+ text: "The corridor stretches into shadow. A lone sentinel blocks your path.",
52474
+ backgroundKey: "corridor",
52475
+ portraitKey: "guide",
52476
+ choices: [
52477
+ { label: "Approach the sentinel.", nextId: "meet" },
52478
+ { label: "Turn back.", nextId: "retreat" }
52479
+ ]
52480
+ },
52481
+ {
52482
+ id: "meet",
52483
+ speaker: "Sentinel",
52484
+ text: "You carry the old marks. Speak your purpose, traveler.",
52485
+ backgroundKey: "forge",
52486
+ portraitKey: "rival",
52487
+ choices: [
52488
+ { label: "I seek the core.", nextId: "end" },
52489
+ { label: "I am only passing through.", nextId: "retreat" }
52490
+ ]
52491
+ },
52492
+ {
52493
+ id: "retreat",
52494
+ speaker: "Narrator",
52495
+ text: "You withdraw into the dark. The path will wait for braver feet.",
52496
+ backgroundKey: "corridor",
52497
+ choices: [{ label: "Begin again.", nextId: "start" }]
52498
+ },
52499
+ {
52500
+ id: "end",
52501
+ speaker: "Sentinel",
52502
+ text: "Then the way is open. Walk it well.",
52503
+ backgroundKey: "core",
52504
+ portraitKey: "rival",
52505
+ choices: [{ label: "Begin again.", nextId: "start" }]
52506
+ }
52507
+ ];
52508
+ VisualNovelBoard.displayName = "VisualNovelBoard";
52509
+ }
52510
+ });
52511
+ function VisualNovelTemplate({
52512
+ entity,
52513
+ title = "Visual Novel",
52514
+ nodes,
52515
+ currentNodeId,
52516
+ typewriterSpeed,
52517
+ portraitScale,
52518
+ chooseEvent,
52519
+ advanceEvent,
52520
+ restartEvent,
52521
+ className
52522
+ }) {
52523
+ const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
52524
+ return /* @__PURE__ */ jsxs(
52525
+ Box,
52526
+ {
52527
+ display: "flex",
52528
+ fullHeight: true,
52529
+ className: cn("visual-novel-template flex-col", className),
52530
+ children: [
52531
+ /* @__PURE__ */ jsx(
52532
+ HStack,
52533
+ {
52534
+ gap: "sm",
52535
+ align: "center",
52536
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
52537
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
52538
+ }
52539
+ ),
52540
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
52541
+ VisualNovelBoard,
52542
+ {
52543
+ entity: resolved,
52544
+ nodes,
52545
+ currentNodeId,
52546
+ typewriterSpeed,
52547
+ portraitScale,
52548
+ chooseEvent,
52549
+ advanceEvent,
52550
+ restartEvent,
52551
+ className: "h-full"
52552
+ }
52553
+ ) })
52554
+ ]
52555
+ }
52556
+ );
52557
+ }
52558
+ var init_VisualNovelTemplate = __esm({
52559
+ "components/game/templates/VisualNovelTemplate.tsx"() {
52560
+ init_cn();
52561
+ init_Box();
52562
+ init_Stack();
52563
+ init_Typography();
52564
+ init_VisualNovelBoard();
52565
+ VisualNovelTemplate.displayName = "VisualNovelTemplate";
52566
+ }
52567
+ });
51168
52568
  function heroPosition(h) {
51169
52569
  if ("position" in h && h.position != null) return h.position;
51170
52570
  return vec2(h.position);
@@ -51505,48 +52905,48 @@ function WorldMapTemplate({
51505
52905
  }
51506
52906
  );
51507
52907
  }
51508
- var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
52908
+ var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
51509
52909
  var init_WorldMapTemplate = __esm({
51510
52910
  "components/game/templates/WorldMapTemplate.tsx"() {
51511
52911
  init_WorldMapBoard();
51512
- CDN7 = "https://almadar-kflow-assets.web.app/shared";
52912
+ CDN5 = "https://almadar-kflow-assets.web.app/shared";
51513
52913
  DEFAULT_WORLDMAP_TILES = [
51514
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51515
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51516
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
51517
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51518
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51519
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51520
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51521
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51522
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51523
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
51524
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
51525
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51526
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
51527
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51528
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51529
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51530
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51531
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51532
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
51533
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51534
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51535
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
51536
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
51537
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
51538
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
52914
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52915
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52916
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52917
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52918
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52919
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52920
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52921
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52922
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52923
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52924
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52925
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52926
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
52927
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52928
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52929
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52930
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52931
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52932
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
52933
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52934
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52935
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52936
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52937
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52938
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
51539
52939
  ];
51540
52940
  DEFAULT_WORLDMAP_UNITS = [
51541
- { id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${CDN7}/sprite-sheets/amir-sprite-sheet-se.png` },
51542
- { id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${CDN7}/sprite-sheets/archivist-sprite-sheet-se.png` }
52941
+ { id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${CDN5}/sprite-sheets/amir-sprite-sheet-se.png` },
52942
+ { id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png` }
51543
52943
  ];
51544
52944
  DEFAULT_WORLDMAP_FEATURES = [
51545
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
51546
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
52945
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
52946
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
51547
52947
  ];
51548
52948
  DEFAULT_WORLDMAP_MANIFEST = {
51549
- baseUrl: CDN7,
52949
+ baseUrl: CDN5,
51550
52950
  terrains: {
51551
52951
  grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
51552
52952
  water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
@@ -51576,8 +52976,8 @@ function XPBar({
51576
52976
  }) {
51577
52977
  const sizes = sizeMap18[size];
51578
52978
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
51579
- const [fillWidth, setFillWidth] = React76.useState(animated ? 0 : percentage);
51580
- React76.useEffect(() => {
52979
+ const [fillWidth, setFillWidth] = React79.useState(animated ? 0 : percentage);
52980
+ React79.useEffect(() => {
51581
52981
  if (!animated) {
51582
52982
  setFillWidth(percentage);
51583
52983
  return;
@@ -51650,7 +53050,7 @@ var init_XPBar = __esm({
51650
53050
  }
51651
53051
  });
51652
53052
  function lazyThree(name, loader) {
51653
- const Lazy = React76__default.lazy(
53053
+ const Lazy = React79__default.lazy(
51654
53054
  () => loader().then((m) => {
51655
53055
  const Resolved = m[name];
51656
53056
  if (!Resolved) {
@@ -51662,13 +53062,13 @@ function lazyThree(name, loader) {
51662
53062
  })
51663
53063
  );
51664
53064
  function ThreeWrapper(props) {
51665
- return React76__default.createElement(
53065
+ return React79__default.createElement(
51666
53066
  ThreeBoundary,
51667
53067
  { name },
51668
- React76__default.createElement(
51669
- React76__default.Suspense,
53068
+ React79__default.createElement(
53069
+ React79__default.Suspense,
51670
53070
  { fallback: null },
51671
- React76__default.createElement(Lazy, props)
53071
+ React79__default.createElement(Lazy, props)
51672
53072
  )
51673
53073
  );
51674
53074
  }
@@ -51712,7 +53112,10 @@ var init_component_registry_generated = __esm({
51712
53112
  init_CalendarGrid();
51713
53113
  init_CanvasEffect();
51714
53114
  init_Card();
53115
+ init_CardBattlerBoard();
53116
+ init_CardBattlerTemplate();
51715
53117
  init_CardGrid();
53118
+ init_CardHand();
51716
53119
  init_Carousel();
51717
53120
  init_CaseStudyCard();
51718
53121
  init_CaseStudyOrganism();
@@ -51723,6 +53126,8 @@ var init_component_registry_generated = __esm({
51723
53126
  init_ChartLegend();
51724
53127
  init_Checkbox();
51725
53128
  init_ChoiceButton();
53129
+ init_CityBuilderBoard();
53130
+ init_CityBuilderTemplate();
51726
53131
  init_ClassifierBoard();
51727
53132
  init_CodeBlock();
51728
53133
  init_CodeRunnerPanel();
@@ -51943,6 +53348,8 @@ var init_component_registry_generated = __esm({
51943
53348
  init_Toast();
51944
53349
  init_ToastSlot();
51945
53350
  init_Tooltip();
53351
+ init_TopDownShooterBoard();
53352
+ init_TopDownShooterTemplate();
51946
53353
  init_TowerDefenseBoard();
51947
53354
  init_TowerDefenseTemplate();
51948
53355
  init_TraitFrame();
@@ -51958,6 +53365,8 @@ var init_component_registry_generated = __esm({
51958
53365
  init_UploadDropZone();
51959
53366
  init_VersionDiff();
51960
53367
  init_ViolationAlert();
53368
+ init_VisualNovelBoard();
53369
+ init_VisualNovelTemplate();
51961
53370
  init_VoteStack();
51962
53371
  init_WaypointMarker();
51963
53372
  init_WizardContainer();
@@ -51966,7 +53375,7 @@ var init_component_registry_generated = __esm({
51966
53375
  init_WorldMapBoard();
51967
53376
  init_WorldMapTemplate();
51968
53377
  init_XPBar();
51969
- ThreeBoundary = class extends React76__default.Component {
53378
+ ThreeBoundary = class extends React79__default.Component {
51970
53379
  constructor() {
51971
53380
  super(...arguments);
51972
53381
  __publicField(this, "state", { failed: false });
@@ -51976,7 +53385,7 @@ var init_component_registry_generated = __esm({
51976
53385
  }
51977
53386
  render() {
51978
53387
  if (this.state.failed) {
51979
- return React76__default.createElement(
53388
+ return React79__default.createElement(
51980
53389
  "div",
51981
53390
  {
51982
53391
  "data-testid": "three-unavailable",
@@ -52032,7 +53441,10 @@ var init_component_registry_generated = __esm({
52032
53441
  "CalendarGrid": CalendarGrid,
52033
53442
  "CanvasEffect": CanvasEffect,
52034
53443
  "Card": Card,
53444
+ "CardBattlerBoard": CardBattlerBoard,
53445
+ "CardBattlerTemplate": CardBattlerTemplate,
52035
53446
  "CardGrid": CardGrid,
53447
+ "CardHand": CardHand,
52036
53448
  "Carousel": Carousel,
52037
53449
  "CaseStudyCard": CaseStudyCard,
52038
53450
  "CaseStudyOrganism": CaseStudyOrganism,
@@ -52043,6 +53455,8 @@ var init_component_registry_generated = __esm({
52043
53455
  "ChartLegend": ChartLegend,
52044
53456
  "Checkbox": Checkbox,
52045
53457
  "ChoiceButton": ChoiceButton,
53458
+ "CityBuilderBoard": CityBuilderBoard,
53459
+ "CityBuilderTemplate": CityBuilderTemplate,
52046
53460
  "ClassifierBoard": ClassifierBoard,
52047
53461
  "CodeBlock": CodeBlock,
52048
53462
  "CodeRunnerPanel": CodeRunnerPanel,
@@ -52275,6 +53689,8 @@ var init_component_registry_generated = __esm({
52275
53689
  "Toast": Toast,
52276
53690
  "ToastSlot": ToastSlot,
52277
53691
  "Tooltip": Tooltip,
53692
+ "TopDownShooterBoard": TopDownShooterBoard,
53693
+ "TopDownShooterTemplate": TopDownShooterTemplate,
52278
53694
  "TowerDefenseBoard": TowerDefenseBoard,
52279
53695
  "TowerDefenseTemplate": TowerDefenseTemplate,
52280
53696
  "TraitFrame": TraitFrame,
@@ -52291,6 +53707,8 @@ var init_component_registry_generated = __esm({
52291
53707
  "VStack": VStack,
52292
53708
  "VersionDiff": VersionDiff,
52293
53709
  "ViolationAlert": ViolationAlert,
53710
+ "VisualNovelBoard": VisualNovelBoard,
53711
+ "VisualNovelTemplate": VisualNovelTemplate,
52294
53712
  "VoteStack": VoteStack,
52295
53713
  "WaypointMarker": WaypointMarker,
52296
53714
  "WizardContainer": WizardContainer,
@@ -52317,7 +53735,7 @@ function SuspenseConfigProvider({
52317
53735
  config,
52318
53736
  children
52319
53737
  }) {
52320
- return React76__default.createElement(
53738
+ return React79__default.createElement(
52321
53739
  SuspenseConfigContext.Provider,
52322
53740
  { value: config },
52323
53741
  children
@@ -52807,7 +54225,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
52807
54225
  const key = `${parentId}-${index}-trait:${traitName}`;
52808
54226
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
52809
54227
  }
52810
- return /* @__PURE__ */ jsx(React76__default.Fragment, { children: child }, `${parentId}-${index}`);
54228
+ return /* @__PURE__ */ jsx(React79__default.Fragment, { children: child }, `${parentId}-${index}`);
52811
54229
  }
52812
54230
  if (!child || typeof child !== "object") return null;
52813
54231
  const childId = `${parentId}-${index}`;
@@ -52847,14 +54265,14 @@ function isPatternConfig(value) {
52847
54265
  if (value === null || value === void 0) return false;
52848
54266
  if (typeof value !== "object") return false;
52849
54267
  if (Array.isArray(value)) return false;
52850
- if (React76__default.isValidElement(value)) return false;
54268
+ if (React79__default.isValidElement(value)) return false;
52851
54269
  if (value instanceof Date) return false;
52852
54270
  if (typeof value === "function") return false;
52853
54271
  const record = value;
52854
54272
  return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
52855
54273
  }
52856
54274
  function isPlainConfigObject(value) {
52857
- if (React76__default.isValidElement(value)) return false;
54275
+ if (React79__default.isValidElement(value)) return false;
52858
54276
  if (value instanceof Date) return false;
52859
54277
  const proto = Object.getPrototypeOf(value);
52860
54278
  return proto === Object.prototype || proto === null;
@@ -52975,6 +54393,22 @@ function SlotContentRenderer({
52975
54393
  const childrenIsRenderFn = typeof incomingChildren === "function";
52976
54394
  const { children: _childrenConfig, ...restPropsNoChildren } = content.props;
52977
54395
  const restProps = childrenIsRenderFn ? { ...restPropsNoChildren, children: incomingChildren } : restPropsNoChildren;
54396
+ const nodeSlotOverrides = {};
54397
+ for (const slotKey of CONTENT_NODE_SLOTS) {
54398
+ const slotVal = restProps[slotKey];
54399
+ if (slotVal === void 0 || slotVal === null) continue;
54400
+ if (React79__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
54401
+ if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
54402
+ nodeSlotOverrides[slotKey] = renderPatternChildren(
54403
+ slotVal,
54404
+ onDismiss,
54405
+ `${content.id}-${slotKey}`,
54406
+ `${myPath}.${slotKey}`,
54407
+ content.sourceTrait,
54408
+ { slot: content.slot, transitionEvent: content.transitionEvent, fromState: content.fromState, entity: content.entity }
54409
+ );
54410
+ }
54411
+ }
52978
54412
  const renderedProps = renderPatternProps(restProps, onDismiss);
52979
54413
  const patternDef = getPatternDefinition$1(content.pattern);
52980
54414
  const propsSchema = patternDef?.propsSchema;
@@ -53005,6 +54439,9 @@ function SlotContentRenderer({
53005
54439
  }
53006
54440
  }
53007
54441
  const finalProps = renderedProps;
54442
+ for (const [k, v] of Object.entries(nodeSlotOverrides)) {
54443
+ finalProps[k] = v;
54444
+ }
53008
54445
  const resolvedItems = Array.isArray(
53009
54446
  finalProps.entity
53010
54447
  ) ? finalProps.entity : null;
@@ -53125,7 +54562,7 @@ function UISlotRenderer({
53125
54562
  }
53126
54563
  return wrapped;
53127
54564
  }
53128
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, FORM_PATTERNS, SELF_OVERLAY_PATTERNS, PATTERNS_WITH_CHILDREN;
54565
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, FORM_PATTERNS, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
53129
54566
  var init_UISlotRenderer = __esm({
53130
54567
  "components/core/organisms/UISlotRenderer.tsx"() {
53131
54568
  "use client";
@@ -53162,6 +54599,16 @@ var init_UISlotRenderer = __esm({
53162
54599
  "wizard-step"
53163
54600
  ]);
53164
54601
  SELF_OVERLAY_PATTERNS = /* @__PURE__ */ new Set(["modal", "confirm-dialog"]);
54602
+ CONTENT_NODE_SLOTS = /* @__PURE__ */ new Set([
54603
+ "logo",
54604
+ "master",
54605
+ "detail",
54606
+ "trigger",
54607
+ "content",
54608
+ "addons",
54609
+ "hud",
54610
+ "fallback"
54611
+ ]);
53165
54612
  PATTERNS_WITH_CHILDREN = /* @__PURE__ */ new Set([
53166
54613
  "stack",
53167
54614
  "vstack",
@@ -53738,7 +55185,11 @@ init_CastleBoard();
53738
55185
  init_PlatformerBoard();
53739
55186
  init_TowerDefenseBoard();
53740
55187
  init_RoguelikeBoard();
55188
+ init_TopDownShooterBoard();
55189
+ init_CityBuilderBoard();
53741
55190
  init_GameBoard3D();
55191
+ init_VisualNovelBoard();
55192
+ init_CardBattlerBoard();
53742
55193
  init_TraitStateViewer();
53743
55194
  init_TraitSlot();
53744
55195
 
@@ -54314,6 +55765,10 @@ init_WorldMapTemplate();
54314
55765
  init_PlatformerTemplate();
54315
55766
  init_TowerDefenseTemplate();
54316
55767
  init_RoguelikeTemplate();
55768
+ init_TopDownShooterTemplate();
55769
+ init_CityBuilderTemplate();
55770
+ init_VisualNovelTemplate();
55771
+ init_CardBattlerTemplate();
54317
55772
  init_LandingPageTemplate();
54318
55773
  init_PricingPageTemplate();
54319
55774
  init_FeatureDetailPageTemplate();
@@ -54322,4 +55777,4 @@ init_AboutPageTemplate();
54322
55777
  // components/index.ts
54323
55778
  init_cn();
54324
55779
 
54325
- export { ALL_PRESETS, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameBoard3D, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HealthPanel, HeroOrganism, HeroSection, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerBoard, PlatformerCanvas, PlatformerTemplate, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RoguelikeBoard, RoguelikeTemplate, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TowerDefenseBoard, TowerDefenseTemplate, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, drawSprite, generateCombatMessage, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseLessonSegments, parseMarkdownWithCodeBlocks, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, toCodeLanguage, transitionAnimation, useAnchorRect, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };
55780
+ export { ALL_PRESETS, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBattlerBoard, CardBattlerTemplate, CardBody, CardContent, CardFooter, CardGrid, CardHand, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, CityBuilderBoard, CityBuilderTemplate, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameBoard3D, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HealthPanel, HeroOrganism, HeroSection, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerBoard, PlatformerCanvas, PlatformerTemplate, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RoguelikeBoard, RoguelikeTemplate, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TopDownShooterBoard, TopDownShooterTemplate, TowerDefenseBoard, TowerDefenseTemplate, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VisualNovelBoard, VisualNovelTemplate, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, drawSprite, generateCombatMessage, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseLessonSegments, parseMarkdownWithCodeBlocks, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, toCodeLanguage, transitionAnimation, useAnchorRect, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };