@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
package/dist/avl/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import * as React90 from 'react';
3
- import React90__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
2
+ import * as React93 from 'react';
3
+ import React93__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
4
4
  import { OrbitalProvider, EventBusContext, useTraitScope, VerificationProvider, TraitScopeProvider } from '@almadar/ui/providers';
5
5
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
6
6
  import ELK from 'elkjs/lib/elk.bundled.js';
@@ -3470,7 +3470,7 @@ var init_Box = __esm({
3470
3470
  fixed: "fixed",
3471
3471
  sticky: "sticky"
3472
3472
  };
3473
- Box = React90__default.forwardRef(
3473
+ Box = React93__default.forwardRef(
3474
3474
  ({
3475
3475
  padding,
3476
3476
  paddingX,
@@ -3520,7 +3520,7 @@ var init_Box = __esm({
3520
3520
  onMouseLeave?.(e);
3521
3521
  }, [hoverEvent, eventBus, onMouseLeave]);
3522
3522
  const isClickable = action || onClick;
3523
- return React90__default.createElement(
3523
+ return React93__default.createElement(
3524
3524
  Component2,
3525
3525
  {
3526
3526
  ref,
@@ -4110,7 +4110,7 @@ var init_MiniStateMachine = __esm({
4110
4110
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
4111
4111
  const tc = transitionCounts[s.name] ?? 0;
4112
4112
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
4113
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
4113
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
4114
4114
  /* @__PURE__ */ jsx(
4115
4115
  AvlState,
4116
4116
  {
@@ -4485,7 +4485,7 @@ function loadLib(key, importer) {
4485
4485
  return p2;
4486
4486
  }
4487
4487
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4488
- const Lazy = React90__default.lazy(async () => {
4488
+ const Lazy = React93__default.lazy(async () => {
4489
4489
  const lib = await loadLib(libKey, importer);
4490
4490
  const Comp = pick(lib);
4491
4491
  if (!Comp) {
@@ -4495,7 +4495,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4495
4495
  return { default: Comp };
4496
4496
  });
4497
4497
  const Wrapped = (props) => /* @__PURE__ */ jsx(
4498
- React90__default.Suspense,
4498
+ React93__default.Suspense,
4499
4499
  {
4500
4500
  fallback: /* @__PURE__ */ jsx(
4501
4501
  "span",
@@ -5221,7 +5221,7 @@ var init_Icon = __esm({
5221
5221
  const directIcon = typeof icon === "string" ? void 0 : icon;
5222
5222
  const effectiveName = typeof icon === "string" ? icon : name;
5223
5223
  const family = useIconFamily();
5224
- const RenderedComponent = React90__default.useMemo(() => {
5224
+ const RenderedComponent = React93__default.useMemo(() => {
5225
5225
  if (directIcon) return null;
5226
5226
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
5227
5227
  }, [directIcon, effectiveName, family]);
@@ -5280,7 +5280,7 @@ function resolveIconProp(value, sizeClass) {
5280
5280
  const IconComp = value;
5281
5281
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
5282
5282
  }
5283
- if (React90__default.isValidElement(value)) {
5283
+ if (React93__default.isValidElement(value)) {
5284
5284
  return value;
5285
5285
  }
5286
5286
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -5356,7 +5356,7 @@ var init_Button = __esm({
5356
5356
  md: "h-icon-default w-icon-default",
5357
5357
  lg: "h-icon-default w-icon-default"
5358
5358
  };
5359
- Button = React90__default.forwardRef(
5359
+ Button = React93__default.forwardRef(
5360
5360
  ({
5361
5361
  className,
5362
5362
  variant = "primary",
@@ -5421,7 +5421,7 @@ var Dialog;
5421
5421
  var init_Dialog = __esm({
5422
5422
  "components/core/atoms/Dialog.tsx"() {
5423
5423
  init_cn();
5424
- Dialog = React90__default.forwardRef(
5424
+ Dialog = React93__default.forwardRef(
5425
5425
  ({
5426
5426
  role = "dialog",
5427
5427
  "aria-modal": ariaModal = true,
@@ -5916,7 +5916,7 @@ var init_Badge = __esm({
5916
5916
  md: "px-2.5 py-1 text-sm",
5917
5917
  lg: "px-3 py-1.5 text-base"
5918
5918
  };
5919
- Badge = React90__default.forwardRef(
5919
+ Badge = React93__default.forwardRef(
5920
5920
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
5921
5921
  const iconSizes3 = {
5922
5922
  sm: "h-icon-default w-icon-default",
@@ -6252,7 +6252,7 @@ var init_SvgFlow = __esm({
6252
6252
  width = 100,
6253
6253
  height = 100
6254
6254
  }) => {
6255
- const markerId = React90__default.useMemo(() => {
6255
+ const markerId = React93__default.useMemo(() => {
6256
6256
  flowIdCounter += 1;
6257
6257
  return `almadar-flow-arrow-${flowIdCounter}`;
6258
6258
  }, []);
@@ -6845,7 +6845,7 @@ var init_SvgRing = __esm({
6845
6845
  width = 100,
6846
6846
  height = 100
6847
6847
  }) => {
6848
- const gradientId = React90__default.useMemo(() => {
6848
+ const gradientId = React93__default.useMemo(() => {
6849
6849
  ringIdCounter += 1;
6850
6850
  return `almadar-ring-glow-${ringIdCounter}`;
6851
6851
  }, []);
@@ -7026,7 +7026,7 @@ var init_Input = __esm({
7026
7026
  init_cn();
7027
7027
  init_Icon();
7028
7028
  init_useEventBus();
7029
- Input = React90__default.forwardRef(
7029
+ Input = React93__default.forwardRef(
7030
7030
  ({
7031
7031
  className,
7032
7032
  inputType,
@@ -7186,7 +7186,7 @@ var Label;
7186
7186
  var init_Label = __esm({
7187
7187
  "components/core/atoms/Label.tsx"() {
7188
7188
  init_cn();
7189
- Label = React90__default.forwardRef(
7189
+ Label = React93__default.forwardRef(
7190
7190
  ({ className, required, children, ...props }, ref) => {
7191
7191
  return /* @__PURE__ */ jsxs(
7192
7192
  "label",
@@ -7213,7 +7213,7 @@ var init_Textarea = __esm({
7213
7213
  "components/core/atoms/Textarea.tsx"() {
7214
7214
  init_cn();
7215
7215
  init_useEventBus();
7216
- Textarea = React90__default.forwardRef(
7216
+ Textarea = React93__default.forwardRef(
7217
7217
  ({ className, error, onChange, ...props }, ref) => {
7218
7218
  const eventBus = useEventBus();
7219
7219
  const handleChange = (e) => {
@@ -7452,7 +7452,7 @@ var init_Select = __esm({
7452
7452
  init_cn();
7453
7453
  init_Icon();
7454
7454
  init_useEventBus();
7455
- Select = React90__default.forwardRef(
7455
+ Select = React93__default.forwardRef(
7456
7456
  (props, _ref) => {
7457
7457
  const { multiple, searchable, clearable } = props;
7458
7458
  if (multiple || searchable || clearable) {
@@ -7469,7 +7469,7 @@ var init_Checkbox = __esm({
7469
7469
  "components/core/atoms/Checkbox.tsx"() {
7470
7470
  init_cn();
7471
7471
  init_useEventBus();
7472
- Checkbox = React90__default.forwardRef(
7472
+ Checkbox = React93__default.forwardRef(
7473
7473
  ({ className, label, id, onChange, ...props }, ref) => {
7474
7474
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
7475
7475
  const eventBus = useEventBus();
@@ -7523,7 +7523,7 @@ var init_Spinner = __esm({
7523
7523
  md: "h-6 w-6",
7524
7524
  lg: "h-8 w-8"
7525
7525
  };
7526
- Spinner = React90__default.forwardRef(
7526
+ Spinner = React93__default.forwardRef(
7527
7527
  ({ className, size = "md", overlay, ...props }, ref) => {
7528
7528
  if (overlay) {
7529
7529
  return /* @__PURE__ */ jsx(
@@ -7613,7 +7613,7 @@ var init_Card = __esm({
7613
7613
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
7614
7614
  "tile-image-first": "p-0 overflow-hidden"
7615
7615
  };
7616
- Card = React90__default.forwardRef(
7616
+ Card = React93__default.forwardRef(
7617
7617
  ({
7618
7618
  className,
7619
7619
  variant = "bordered",
@@ -7661,9 +7661,9 @@ var init_Card = __esm({
7661
7661
  }
7662
7662
  );
7663
7663
  Card.displayName = "Card";
7664
- CardHeader = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7664
+ CardHeader = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7665
7665
  CardHeader.displayName = "CardHeader";
7666
- CardTitle = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7666
+ CardTitle = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7667
7667
  "h3",
7668
7668
  {
7669
7669
  ref,
@@ -7676,11 +7676,11 @@ var init_Card = __esm({
7676
7676
  }
7677
7677
  ));
7678
7678
  CardTitle.displayName = "CardTitle";
7679
- CardContent = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7679
+ CardContent = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7680
7680
  CardContent.displayName = "CardContent";
7681
7681
  CardBody = CardContent;
7682
7682
  CardBody.displayName = "CardBody";
7683
- CardFooter = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7683
+ CardFooter = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7684
7684
  "div",
7685
7685
  {
7686
7686
  ref,
@@ -7735,7 +7735,7 @@ var init_FilterPill = __esm({
7735
7735
  md: "w-3.5 h-3.5",
7736
7736
  lg: "w-4 h-4"
7737
7737
  };
7738
- FilterPill = React90__default.forwardRef(
7738
+ FilterPill = React93__default.forwardRef(
7739
7739
  ({
7740
7740
  className,
7741
7741
  variant = "default",
@@ -7864,8 +7864,8 @@ var init_Avatar = __esm({
7864
7864
  actionPayload
7865
7865
  }) => {
7866
7866
  const eventBus = useEventBus();
7867
- const [imgFailed, setImgFailed] = React90__default.useState(false);
7868
- React90__default.useEffect(() => {
7867
+ const [imgFailed, setImgFailed] = React93__default.useState(false);
7868
+ React93__default.useEffect(() => {
7869
7869
  setImgFailed(false);
7870
7870
  }, [src]);
7871
7871
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -8250,7 +8250,7 @@ var init_Radio = __esm({
8250
8250
  md: "w-2.5 h-2.5",
8251
8251
  lg: "w-3 h-3"
8252
8252
  };
8253
- Radio = React90__default.forwardRef(
8253
+ Radio = React93__default.forwardRef(
8254
8254
  ({
8255
8255
  label,
8256
8256
  helperText,
@@ -8267,12 +8267,12 @@ var init_Radio = __esm({
8267
8267
  onChange,
8268
8268
  ...props
8269
8269
  }, ref) => {
8270
- const reactId = React90__default.useId();
8270
+ const reactId = React93__default.useId();
8271
8271
  const baseId = id || `radio-${reactId}`;
8272
8272
  const hasError = !!error;
8273
8273
  const eventBus = useEventBus();
8274
- const [selected, setSelected] = React90__default.useState(value);
8275
- React90__default.useEffect(() => {
8274
+ const [selected, setSelected] = React93__default.useState(value);
8275
+ React93__default.useEffect(() => {
8276
8276
  if (value !== void 0) setSelected(value);
8277
8277
  }, [value]);
8278
8278
  const pick = (next, e) => {
@@ -8454,7 +8454,7 @@ var init_Switch = __esm({
8454
8454
  "components/core/atoms/Switch.tsx"() {
8455
8455
  "use client";
8456
8456
  init_cn();
8457
- Switch = React90.forwardRef(
8457
+ Switch = React93.forwardRef(
8458
8458
  ({
8459
8459
  checked,
8460
8460
  defaultChecked = false,
@@ -8465,10 +8465,10 @@ var init_Switch = __esm({
8465
8465
  name,
8466
8466
  className
8467
8467
  }, ref) => {
8468
- const [isChecked, setIsChecked] = React90.useState(
8468
+ const [isChecked, setIsChecked] = React93.useState(
8469
8469
  checked !== void 0 ? checked : defaultChecked
8470
8470
  );
8471
- React90.useEffect(() => {
8471
+ React93.useEffect(() => {
8472
8472
  if (checked !== void 0) {
8473
8473
  setIsChecked(checked);
8474
8474
  }
@@ -8737,7 +8737,7 @@ var Aside;
8737
8737
  var init_Aside = __esm({
8738
8738
  "components/core/atoms/Aside.tsx"() {
8739
8739
  init_cn();
8740
- Aside = React90__default.forwardRef(
8740
+ Aside = React93__default.forwardRef(
8741
8741
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
8742
8742
  );
8743
8743
  Aside.displayName = "Aside";
@@ -8815,8 +8815,8 @@ var init_LawReferenceTooltip = __esm({
8815
8815
  className
8816
8816
  }) => {
8817
8817
  const { t } = useTranslate();
8818
- const [isVisible, setIsVisible] = React90__default.useState(false);
8819
- const timeoutRef = React90__default.useRef(null);
8818
+ const [isVisible, setIsVisible] = React93__default.useState(false);
8819
+ const timeoutRef = React93__default.useRef(null);
8820
8820
  const handleMouseEnter = () => {
8821
8821
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8822
8822
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -8825,7 +8825,7 @@ var init_LawReferenceTooltip = __esm({
8825
8825
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8826
8826
  setIsVisible(false);
8827
8827
  };
8828
- React90__default.useEffect(() => {
8828
+ React93__default.useEffect(() => {
8829
8829
  return () => {
8830
8830
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8831
8831
  };
@@ -9035,7 +9035,7 @@ var init_StatusDot = __esm({
9035
9035
  md: "w-2.5 h-2.5",
9036
9036
  lg: "w-3 h-3"
9037
9037
  };
9038
- StatusDot = React90__default.forwardRef(
9038
+ StatusDot = React93__default.forwardRef(
9039
9039
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
9040
9040
  return /* @__PURE__ */ jsx(
9041
9041
  "span",
@@ -9089,7 +9089,7 @@ var init_TrendIndicator = __esm({
9089
9089
  down: "trending-down",
9090
9090
  flat: "arrow-right"
9091
9091
  };
9092
- TrendIndicator = React90__default.forwardRef(
9092
+ TrendIndicator = React93__default.forwardRef(
9093
9093
  ({
9094
9094
  className,
9095
9095
  value,
@@ -9156,7 +9156,7 @@ var init_RangeSlider = __esm({
9156
9156
  md: "w-4 h-4",
9157
9157
  lg: "w-5 h-5"
9158
9158
  };
9159
- RangeSlider = React90__default.forwardRef(
9159
+ RangeSlider = React93__default.forwardRef(
9160
9160
  ({
9161
9161
  className,
9162
9162
  min = 0,
@@ -9664,7 +9664,7 @@ var init_ContentSection = __esm({
9664
9664
  md: "py-16",
9665
9665
  lg: "py-24"
9666
9666
  };
9667
- ContentSection = React90__default.forwardRef(
9667
+ ContentSection = React93__default.forwardRef(
9668
9668
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
9669
9669
  return /* @__PURE__ */ jsx(
9670
9670
  Box,
@@ -10198,7 +10198,7 @@ var init_AnimatedReveal = __esm({
10198
10198
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
10199
10199
  "none": {}
10200
10200
  };
10201
- AnimatedReveal = React90__default.forwardRef(
10201
+ AnimatedReveal = React93__default.forwardRef(
10202
10202
  ({
10203
10203
  trigger = "scroll",
10204
10204
  animation = "fade-up",
@@ -10358,7 +10358,7 @@ var init_AnimatedGraphic = __esm({
10358
10358
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
10359
10359
  "use client";
10360
10360
  init_cn();
10361
- AnimatedGraphic = React90__default.forwardRef(
10361
+ AnimatedGraphic = React93__default.forwardRef(
10362
10362
  ({
10363
10363
  src,
10364
10364
  svgContent,
@@ -10381,7 +10381,7 @@ var init_AnimatedGraphic = __esm({
10381
10381
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
10382
10382
  const resolvedSvg = svgContent ?? fetchedSvg;
10383
10383
  const prevAnimateRef = useRef(animate);
10384
- const setRef = React90__default.useCallback(
10384
+ const setRef = React93__default.useCallback(
10385
10385
  (node) => {
10386
10386
  containerRef.current = node;
10387
10387
  if (typeof ref === "function") ref(node);
@@ -10607,9 +10607,9 @@ function ScoreDisplay({
10607
10607
  ...rest
10608
10608
  }) {
10609
10609
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
10610
- const [displayValue, setDisplayValue] = React90.useState(resolvedValue);
10611
- const [isAnimating, setIsAnimating] = React90.useState(false);
10612
- React90.useEffect(() => {
10610
+ const [displayValue, setDisplayValue] = React93.useState(resolvedValue);
10611
+ const [isAnimating, setIsAnimating] = React93.useState(false);
10612
+ React93.useEffect(() => {
10613
10613
  if (!animated || displayValue === resolvedValue) {
10614
10614
  setDisplayValue(resolvedValue);
10615
10615
  return;
@@ -10692,9 +10692,9 @@ function ControlButton({
10692
10692
  className
10693
10693
  }) {
10694
10694
  const eventBus = useEventBus();
10695
- const [isPressed, setIsPressed] = React90.useState(false);
10695
+ const [isPressed, setIsPressed] = React93.useState(false);
10696
10696
  const actualPressed = pressed ?? isPressed;
10697
- const handlePointerDown = React90.useCallback(
10697
+ const handlePointerDown = React93.useCallback(
10698
10698
  (e) => {
10699
10699
  e.preventDefault();
10700
10700
  if (disabled) return;
@@ -10704,7 +10704,7 @@ function ControlButton({
10704
10704
  },
10705
10705
  [disabled, pressEvent, eventBus, onPress]
10706
10706
  );
10707
- const handlePointerUp = React90.useCallback(
10707
+ const handlePointerUp = React93.useCallback(
10708
10708
  (e) => {
10709
10709
  e.preventDefault();
10710
10710
  if (disabled) return;
@@ -10714,7 +10714,7 @@ function ControlButton({
10714
10714
  },
10715
10715
  [disabled, releaseEvent, eventBus, onRelease]
10716
10716
  );
10717
- const handlePointerLeave = React90.useCallback(
10717
+ const handlePointerLeave = React93.useCallback(
10718
10718
  (e) => {
10719
10719
  if (isPressed) {
10720
10720
  setIsPressed(false);
@@ -11335,8 +11335,8 @@ function XPBar({
11335
11335
  }) {
11336
11336
  const sizes = sizeMap9[size];
11337
11337
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
11338
- const [fillWidth, setFillWidth] = React90.useState(animated ? 0 : percentage);
11339
- React90.useEffect(() => {
11338
+ const [fillWidth, setFillWidth] = React93.useState(animated ? 0 : percentage);
11339
+ React93.useEffect(() => {
11340
11340
  if (!animated) {
11341
11341
  setFillWidth(percentage);
11342
11342
  return;
@@ -11824,9 +11824,9 @@ function MiniMap({
11824
11824
  viewportRect = DEFAULT_VIEWPORT,
11825
11825
  className
11826
11826
  }) {
11827
- const canvasRef = React90.useRef(null);
11828
- const frameRef = React90.useRef(0);
11829
- React90.useEffect(() => {
11827
+ const canvasRef = React93.useRef(null);
11828
+ const frameRef = React93.useRef(0);
11829
+ React93.useEffect(() => {
11830
11830
  const canvas = canvasRef.current;
11831
11831
  if (!canvas) return;
11832
11832
  const ctx = canvas.getContext("2d");
@@ -12015,7 +12015,7 @@ var init_ErrorBoundary = __esm({
12015
12015
  }
12016
12016
  );
12017
12017
  };
12018
- ErrorBoundary = class extends React90__default.Component {
12018
+ ErrorBoundary = class extends React93__default.Component {
12019
12019
  constructor(props) {
12020
12020
  super(props);
12021
12021
  __publicField(this, "reset", () => {
@@ -13050,8 +13050,8 @@ function ActionButtons({
13050
13050
  disabled
13051
13051
  }) {
13052
13052
  const eventBus = useEventBus();
13053
- const [activeButtons, setActiveButtons] = React90.useState(/* @__PURE__ */ new Set());
13054
- const handlePress = React90.useCallback(
13053
+ const [activeButtons, setActiveButtons] = React93.useState(/* @__PURE__ */ new Set());
13054
+ const handlePress = React93.useCallback(
13055
13055
  (id) => {
13056
13056
  setActiveButtons((prev) => new Set(prev).add(id));
13057
13057
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -13059,7 +13059,7 @@ function ActionButtons({
13059
13059
  },
13060
13060
  [actionEvent, eventBus, onAction]
13061
13061
  );
13062
- const handleRelease = React90.useCallback(
13062
+ const handleRelease = React93.useCallback(
13063
13063
  (id) => {
13064
13064
  setActiveButtons((prev) => {
13065
13065
  const next = new Set(prev);
@@ -13696,8 +13696,8 @@ var init_AnimatedCounter = __esm({
13696
13696
  const [displayValue, setDisplayValue] = useState("0");
13697
13697
  const [hasAnimated, setHasAnimated] = useState(false);
13698
13698
  const animate = useCallback(() => {
13699
- const { num: num2, prefix, suffix, decimals } = parseValue(value);
13700
- if (num2 === 0) {
13699
+ const { num: num3, prefix, suffix, decimals } = parseValue(value);
13700
+ if (num3 === 0) {
13701
13701
  setDisplayValue(String(value));
13702
13702
  return;
13703
13703
  }
@@ -13706,7 +13706,7 @@ var init_AnimatedCounter = __esm({
13706
13706
  const elapsed = now2 - startTime;
13707
13707
  const progress = Math.min(elapsed / duration, 1);
13708
13708
  const eased = 1 - Math.pow(1 - progress, 3);
13709
- const current = eased * num2;
13709
+ const current = eased * num3;
13710
13710
  setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
13711
13711
  if (progress < 1) {
13712
13712
  requestAnimationFrame(tick);
@@ -14536,7 +14536,7 @@ function IsometricCanvas({
14536
14536
  // Tuning
14537
14537
  diamondTopY: diamondTopYProp,
14538
14538
  // Remote asset loading
14539
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
14539
+ assetBaseUrl,
14540
14540
  assetManifest
14541
14541
  }) {
14542
14542
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -14615,7 +14615,7 @@ function IsometricCanvas({
14615
14615
  const attackTargetSet = useMemo(() => {
14616
14616
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
14617
14617
  }, [attackTargets]);
14618
- const resolveManifestUrl = useCallback((relativePath) => {
14618
+ const resolveManifestUrl7 = useCallback((relativePath) => {
14619
14619
  if (!relativePath) return void 0;
14620
14620
  if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
14621
14621
  return relativePath;
@@ -14628,7 +14628,7 @@ function IsometricCanvas({
14628
14628
  const url = getTerrainSprite(tile.terrain ?? "");
14629
14629
  if (url) urls.push(url);
14630
14630
  } else {
14631
- const url = resolveManifestUrl(assetManifest?.terrains?.[tile.terrain ?? ""]);
14631
+ const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14632
14632
  if (url) urls.push(url);
14633
14633
  }
14634
14634
  }
@@ -14638,7 +14638,7 @@ function IsometricCanvas({
14638
14638
  const url = getFeatureSprite(feature.type);
14639
14639
  if (url) urls.push(url);
14640
14640
  } else {
14641
- const url = resolveManifestUrl(assetManifest?.features?.[feature.type]);
14641
+ const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
14642
14642
  if (url) urls.push(url);
14643
14643
  }
14644
14644
  }
@@ -14648,13 +14648,13 @@ function IsometricCanvas({
14648
14648
  const url = getUnitSprite(unit);
14649
14649
  if (url) urls.push(url);
14650
14650
  } else if (unit.unitType) {
14651
- const url = resolveManifestUrl(assetManifest?.units?.[unit.unitType]);
14651
+ const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
14652
14652
  if (url) urls.push(url);
14653
14653
  }
14654
14654
  }
14655
14655
  if (assetManifest?.effects) {
14656
14656
  for (const path of Object.values(assetManifest.effects)) {
14657
- const url = resolveManifestUrl(path);
14657
+ const url = resolveManifestUrl7(path);
14658
14658
  if (url) urls.push(url);
14659
14659
  }
14660
14660
  }
@@ -14662,7 +14662,7 @@ function IsometricCanvas({
14662
14662
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
14663
14663
  if (backgroundImage) urls.push(backgroundImage);
14664
14664
  return [...new Set(urls.filter(Boolean))];
14665
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
14665
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
14666
14666
  const { getImage, pendingCount } = useImageCache(spriteUrls);
14667
14667
  useEffect(() => {
14668
14668
  if (typeof window === "undefined") return;
@@ -14686,14 +14686,14 @@ function IsometricCanvas({
14686
14686
  lerpToTarget
14687
14687
  } = useCamera();
14688
14688
  const resolveTerrainSpriteUrl = useCallback((tile) => {
14689
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl(assetManifest?.terrains?.[tile.terrain ?? ""]);
14690
- }, [getTerrainSprite, assetManifest, resolveManifestUrl]);
14689
+ return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14690
+ }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
14691
14691
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
14692
- return getFeatureSprite?.(featureType) || resolveManifestUrl(assetManifest?.features?.[featureType]);
14693
- }, [getFeatureSprite, assetManifest, resolveManifestUrl]);
14692
+ return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
14693
+ }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
14694
14694
  const resolveUnitSpriteUrl = useCallback((unit) => {
14695
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl(assetManifest?.units?.[unit.unitType]) : void 0);
14696
- }, [getUnitSprite, assetManifest, resolveManifestUrl]);
14695
+ return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
14696
+ }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
14697
14697
  const drawMinimap = useCallback(() => {
14698
14698
  if (!showMinimap) return;
14699
14699
  const miniCanvas = minimapRef.current;
@@ -14795,7 +14795,15 @@ function IsometricCanvas({
14795
14795
  const spriteUrl = resolveTerrainSpriteUrl(tile);
14796
14796
  const img = spriteUrl ? getImage(spriteUrl) : null;
14797
14797
  if (img) {
14798
- ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
14798
+ if (img.naturalWidth === 0) {
14799
+ ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
14800
+ } else {
14801
+ const drawW = scaledTileWidth;
14802
+ const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
14803
+ const drawX = pos.x;
14804
+ const drawY = pos.y + scaledTileHeight - drawH;
14805
+ ctx.drawImage(img, drawX, drawY, drawW, drawH);
14806
+ }
14799
14807
  } else {
14800
14808
  const centerX = pos.x + scaledTileWidth / 2;
14801
14809
  const topY = pos.y + scaledDiamondTopY;
@@ -16225,7 +16233,7 @@ var init_CodeBlock = __esm({
16225
16233
  };
16226
16234
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
16227
16235
  HIDDEN_LINE_NUMBERS = { display: "none" };
16228
- CodeBlock = React90__default.memo(
16236
+ CodeBlock = React93__default.memo(
16229
16237
  ({
16230
16238
  code: rawCode,
16231
16239
  language = "text",
@@ -16394,24 +16402,24 @@ var init_CodeBlock = __esm({
16394
16402
  return;
16395
16403
  }
16396
16404
  lineEls.forEach((el) => {
16397
- const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
16398
- if (hiddenLines.has(num2)) {
16405
+ const num3 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
16406
+ if (hiddenLines.has(num3)) {
16399
16407
  el.style.display = "none";
16400
16408
  return;
16401
16409
  }
16402
16410
  el.style.display = "";
16403
16411
  el.style.position = "relative";
16404
16412
  el.style.paddingLeft = "1.2em";
16405
- const region = foldStartMap.get(num2);
16413
+ const region = foldStartMap.get(num3);
16406
16414
  if (!region) return;
16407
- const isCollapsed = collapsed.has(num2);
16415
+ const isCollapsed = collapsed.has(num3);
16408
16416
  const toggle = document.createElement("span");
16409
16417
  toggle.className = "fold-toggle";
16410
16418
  toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
16411
16419
  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%";
16412
16420
  toggle.addEventListener("click", (e) => {
16413
16421
  e.stopPropagation();
16414
- toggleFoldRef.current(num2);
16422
+ toggleFoldRef.current(num3);
16415
16423
  });
16416
16424
  el.insertBefore(toggle, el.firstChild);
16417
16425
  if (isCollapsed) {
@@ -16812,7 +16820,7 @@ var init_MarkdownContent = __esm({
16812
16820
  init_Box();
16813
16821
  init_CodeBlock();
16814
16822
  init_cn();
16815
- MarkdownContent = React90__default.memo(
16823
+ MarkdownContent = React93__default.memo(
16816
16824
  ({ content, direction = "ltr", className }) => {
16817
16825
  const { t: _t } = useTranslate();
16818
16826
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -18129,7 +18137,7 @@ var init_StateMachineView = __esm({
18129
18137
  style: { top: title ? 30 : 0 },
18130
18138
  children: [
18131
18139
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
18132
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React90__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18140
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React93__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18133
18141
  StateNode,
18134
18142
  {
18135
18143
  state,
@@ -22030,8 +22038,8 @@ function EmojiEffect({
22030
22038
  );
22031
22039
  }
22032
22040
  function CanvasEffect({
22033
- effectSpriteUrl = "https://almadar-kflow-assets.web.app/shared/effects/gas/gas00.png",
22034
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/effects/",
22041
+ effectSpriteUrl,
22042
+ assetBaseUrl,
22035
22043
  ...props
22036
22044
  }) {
22037
22045
  const eventBus = useEventBus();
@@ -22074,6 +22082,380 @@ var init_CanvasEffect = __esm({
22074
22082
  CanvasEffect.displayName = "CanvasEffect";
22075
22083
  }
22076
22084
  });
22085
+ function CardHand({
22086
+ cards = DEFAULT_CARDS,
22087
+ selectedId = "",
22088
+ size = "md",
22089
+ onCardClick,
22090
+ cardClickEvent,
22091
+ emptyLabel = "No cards in hand",
22092
+ className
22093
+ }) {
22094
+ const eventBus = useEventBus();
22095
+ const handleClick = React93.useCallback(
22096
+ (card) => {
22097
+ if (card.disabled) return;
22098
+ onCardClick?.(card.id);
22099
+ if (cardClickEvent) {
22100
+ eventBus.emit(`UI:${cardClickEvent}`, { cardId: card.id });
22101
+ }
22102
+ },
22103
+ [onCardClick, cardClickEvent, eventBus]
22104
+ );
22105
+ if (cards.length === 0) {
22106
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center p-4", className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: emptyLabel }) });
22107
+ }
22108
+ const art = artSizeMap[size];
22109
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex flex-wrap gap-2 justify-center items-end", className), children: cards.map((card) => {
22110
+ const selected = selectedId === card.id;
22111
+ return /* @__PURE__ */ jsxs(
22112
+ "button",
22113
+ {
22114
+ type: "button",
22115
+ onClick: () => handleClick(card),
22116
+ disabled: card.disabled,
22117
+ title: card.title,
22118
+ className: cn(
22119
+ "card-hand-card relative flex flex-col items-center rounded-interactive border-2",
22120
+ "bg-card/90 px-1.5 pt-1.5 pb-1 transition-all duration-150",
22121
+ cardSizeMap[size],
22122
+ card.disabled ? "border-border opacity-50 cursor-not-allowed" : "border-accent hover:brightness-125 hover:-translate-y-1 cursor-pointer",
22123
+ selected && "ring-2 ring-foreground ring-offset-1 ring-offset-background -translate-y-1"
22124
+ ),
22125
+ children: [
22126
+ card.cost != null && /* @__PURE__ */ jsx(
22127
+ "span",
22128
+ {
22129
+ className: cn(
22130
+ "absolute -top-2 -left-2 flex items-center justify-center",
22131
+ "min-w-[22px] h-[22px] rounded-full px-1",
22132
+ "bg-info text-foreground text-xs font-bold border border-background"
22133
+ ),
22134
+ children: card.cost
22135
+ }
22136
+ ),
22137
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
22138
+ "img",
22139
+ {
22140
+ src: card.iconUrl,
22141
+ alt: card.title ?? card.id,
22142
+ width: art,
22143
+ height: art,
22144
+ style: { imageRendering: "pixelated", objectFit: "contain" },
22145
+ className: "flex-shrink-0"
22146
+ }
22147
+ ) : /* @__PURE__ */ jsx(
22148
+ Box,
22149
+ {
22150
+ className: "rounded bg-muted/40",
22151
+ style: { width: art, height: art }
22152
+ }
22153
+ ) }),
22154
+ card.title != null && /* @__PURE__ */ jsx(
22155
+ Typography,
22156
+ {
22157
+ variant: "small",
22158
+ className: "w-full truncate text-center text-[10px] leading-tight font-semibold",
22159
+ children: card.title
22160
+ }
22161
+ ),
22162
+ (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: [
22163
+ /* @__PURE__ */ jsx("span", { className: "text-error", children: card.attack != null ? `\u2694${card.attack}` : "" }),
22164
+ /* @__PURE__ */ jsx("span", { className: "text-info", children: card.defense != null ? `\u{1F6E1}${card.defense}` : "" })
22165
+ ] })
22166
+ ]
22167
+ },
22168
+ card.id
22169
+ );
22170
+ }) });
22171
+ }
22172
+ var cardSizeMap, artSizeMap, DEFAULT_CARDS;
22173
+ var init_CardHand = __esm({
22174
+ "components/game/molecules/CardHand.tsx"() {
22175
+ "use client";
22176
+ init_cn();
22177
+ init_useEventBus();
22178
+ init_Box();
22179
+ init_Typography();
22180
+ cardSizeMap = {
22181
+ sm: "w-16 h-24",
22182
+ md: "w-20 h-28",
22183
+ lg: "w-24 h-36"
22184
+ };
22185
+ artSizeMap = {
22186
+ sm: 40,
22187
+ md: 52,
22188
+ lg: 64
22189
+ };
22190
+ DEFAULT_CARDS = [
22191
+ { id: "card-1", title: "Brawler", cost: 1, attack: 2, defense: 1 },
22192
+ { id: "card-2", title: "Guardian", cost: 2, attack: 1, defense: 4 },
22193
+ { id: "card-3", title: "Striker", cost: 3, attack: 5, defense: 2 }
22194
+ ];
22195
+ CardHand.displayName = "CardHand";
22196
+ }
22197
+ });
22198
+ function resolveManifestUrl(manifest, relative) {
22199
+ if (relative == null) return void 0;
22200
+ if (/^https?:\/\//.test(relative)) return relative;
22201
+ const base = manifest?.baseUrl;
22202
+ if (base == null) return relative;
22203
+ const cleanBase = base.replace(/\/$/, "");
22204
+ const cleanRel = relative.replace(/^\//, "");
22205
+ return `${cleanBase}/${cleanRel}`;
22206
+ }
22207
+ function rowToCard(r2) {
22208
+ return {
22209
+ id: str(r2.id),
22210
+ iconKey: r2.iconKey == null ? void 0 : str(r2.iconKey),
22211
+ title: r2.title == null ? void 0 : str(r2.title),
22212
+ cost: r2.cost == null ? void 0 : num(r2.cost),
22213
+ attack: r2.attack == null ? void 0 : num(r2.attack),
22214
+ defense: r2.defense == null ? void 0 : num(r2.defense)
22215
+ };
22216
+ }
22217
+ function toHandCards(cards, manifest, mana) {
22218
+ return cards.map((c) => {
22219
+ const key = c.iconKey ?? c.id;
22220
+ const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
22221
+ return {
22222
+ id: c.id,
22223
+ iconUrl,
22224
+ title: c.title,
22225
+ cost: c.cost,
22226
+ attack: c.attack,
22227
+ defense: c.defense,
22228
+ disabled: c.cost != null && c.cost > mana
22229
+ };
22230
+ });
22231
+ }
22232
+ function CardBattlerBoard({
22233
+ entity,
22234
+ deck: propDeck,
22235
+ hand: propHand,
22236
+ board: propBoard,
22237
+ mana: propMana,
22238
+ maxMana: propMaxMana,
22239
+ turn: propTurn,
22240
+ result: propResult,
22241
+ assetManifest: propAssetManifest,
22242
+ playCardEvent,
22243
+ endTurnEvent,
22244
+ playAgainEvent,
22245
+ gameEndEvent,
22246
+ className
22247
+ }) {
22248
+ const board = boardEntity(entity) ?? {};
22249
+ const eventBus = useEventBus();
22250
+ const { t } = useTranslate();
22251
+ const assetManifest = propAssetManifest ?? board.assetManifest;
22252
+ const entityHand = useMemo(() => rows(board.hand).map(rowToCard), [board.hand]);
22253
+ const rawHand = propHand ?? entityHand;
22254
+ const hand = rawHand.length > 0 ? rawHand : DEFAULT_HAND;
22255
+ const entityBoard = useMemo(() => rows(board.board).map(rowToCard), [board.board]);
22256
+ const playedCards = propBoard ?? entityBoard;
22257
+ const entityDeck = useMemo(() => rows(board.deck).map(rowToCard), [board.deck]);
22258
+ const deck = propDeck ?? entityDeck;
22259
+ const mana = propMana ?? num(board.mana, 3);
22260
+ const maxMana = propMaxMana ?? num(board.maxMana, 3);
22261
+ const turn = propTurn ?? num(board.turn, 1);
22262
+ const result = propResult ?? (str(board.result) || "none");
22263
+ const handCards = useMemo(() => toHandCards(hand, assetManifest, mana), [hand, assetManifest, mana]);
22264
+ const boardCards = useMemo(() => toHandCards(playedCards, assetManifest, mana), [playedCards, assetManifest, mana]);
22265
+ const emittedGameEnd = useRef(false);
22266
+ if (result !== "none" && !emittedGameEnd.current) {
22267
+ emittedGameEnd.current = true;
22268
+ if (gameEndEvent) {
22269
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
22270
+ }
22271
+ }
22272
+ if (result === "none") {
22273
+ emittedGameEnd.current = false;
22274
+ }
22275
+ const handlePlayCard = useCallback((cardId) => {
22276
+ if (result !== "none") return;
22277
+ if (playCardEvent) {
22278
+ eventBus.emit(`UI:${playCardEvent}`, { cardId });
22279
+ }
22280
+ }, [result, playCardEvent, eventBus]);
22281
+ const handleEndTurn = useCallback(() => {
22282
+ if (result !== "none") return;
22283
+ if (endTurnEvent) {
22284
+ eventBus.emit(`UI:${endTurnEvent}`, {});
22285
+ }
22286
+ }, [result, endTurnEvent, eventBus]);
22287
+ const handlePlayAgain = useCallback(() => {
22288
+ if (playAgainEvent) {
22289
+ eventBus.emit(`UI:${playAgainEvent}`, {});
22290
+ }
22291
+ }, [playAgainEvent, eventBus]);
22292
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("card-battler-board relative min-h-[600px] bg-background", className), gap: "none", children: [
22293
+ /* @__PURE__ */ jsxs(
22294
+ HStack,
22295
+ {
22296
+ className: "px-4 py-2 border-b border-border bg-surface",
22297
+ gap: "lg",
22298
+ align: "center",
22299
+ children: [
22300
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
22301
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.mana") ?? "Mana" }),
22302
+ /* @__PURE__ */ jsxs(Typography, { variant: "body2", weight: "bold", className: "text-info", children: [
22303
+ mana,
22304
+ " / ",
22305
+ maxMana
22306
+ ] })
22307
+ ] }),
22308
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
22309
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.turn") ?? "Turn" }),
22310
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: turn })
22311
+ ] }),
22312
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
22313
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.deck") ?? "Deck" }),
22314
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: deck.length })
22315
+ ] }),
22316
+ /* @__PURE__ */ jsx(Box, { className: "ml-auto", children: result === "none" && /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleEndTurn, children: t("cb.endTurn") ?? "End Turn" }) })
22317
+ ]
22318
+ }
22319
+ ),
22320
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 relative p-4 overflow-auto", children: [
22321
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", className: "mb-2 uppercase tracking-wide", children: t("cb.battlefield") ?? "Battlefield" }),
22322
+ boardCards.length > 0 ? /* @__PURE__ */ jsx(
22323
+ CardHand,
22324
+ {
22325
+ cards: boardCards,
22326
+ size: "md",
22327
+ className: "justify-start"
22328
+ }
22329
+ ) : /* @__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" }) })
22330
+ ] }),
22331
+ /* @__PURE__ */ jsxs(Box, { className: "border-t border-border bg-surface px-4 py-3", children: [
22332
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", className: "mb-2 uppercase tracking-wide", children: t("cb.hand") ?? "Your Hand" }),
22333
+ /* @__PURE__ */ jsx(
22334
+ CardHand,
22335
+ {
22336
+ cards: handCards,
22337
+ size: "lg",
22338
+ onCardClick: handlePlayCard,
22339
+ emptyLabel: t("cb.emptyHand") ?? "No cards in hand"
22340
+ }
22341
+ )
22342
+ ] }),
22343
+ 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: [
22344
+ /* @__PURE__ */ jsx(
22345
+ Typography,
22346
+ {
22347
+ variant: "h2",
22348
+ className: cn(
22349
+ "text-4xl font-black tracking-widest uppercase",
22350
+ result === "won" ? "text-warning" : "text-error"
22351
+ ),
22352
+ children: result === "won" ? t("cb.victory") ?? "Victory!" : t("cb.defeat") ?? "Defeat!"
22353
+ }
22354
+ ),
22355
+ /* @__PURE__ */ jsx(
22356
+ Button,
22357
+ {
22358
+ variant: "primary",
22359
+ className: "px-8 py-3 font-semibold",
22360
+ onClick: handlePlayAgain,
22361
+ children: t("cb.playAgain") ?? "Play Again"
22362
+ }
22363
+ )
22364
+ ] }) })
22365
+ ] });
22366
+ }
22367
+ var DEFAULT_HAND;
22368
+ var init_CardBattlerBoard = __esm({
22369
+ "components/game/organisms/CardBattlerBoard.tsx"() {
22370
+ "use client";
22371
+ init_cn();
22372
+ init_useEventBus();
22373
+ init_Box();
22374
+ init_Button();
22375
+ init_Typography();
22376
+ init_Stack();
22377
+ init_CardHand();
22378
+ init_boardEntity();
22379
+ DEFAULT_HAND = [
22380
+ { id: "c1", iconKey: "bear", title: "Bear", cost: 3, attack: 5, defense: 4 },
22381
+ { id: "c2", iconKey: "owl", title: "Owl", cost: 1, attack: 2, defense: 1 },
22382
+ { id: "c3", iconKey: "gorilla", title: "Gorilla", cost: 4, attack: 6, defense: 5 },
22383
+ { id: "c4", iconKey: "frog", title: "Frog", cost: 1, attack: 1, defense: 2 },
22384
+ { id: "c5", iconKey: "snake", title: "Snake", cost: 2, attack: 4, defense: 1 }
22385
+ ];
22386
+ CardBattlerBoard.displayName = "CardBattlerBoard";
22387
+ }
22388
+ });
22389
+ function isEntityRow(value) {
22390
+ return value != null && typeof value === "object" && !Array.isArray(value);
22391
+ }
22392
+ function CardBattlerTemplate({
22393
+ entity,
22394
+ title = "Card Battler",
22395
+ deck,
22396
+ hand,
22397
+ board,
22398
+ mana,
22399
+ maxMana,
22400
+ turn,
22401
+ result,
22402
+ assetManifest,
22403
+ playCardEvent,
22404
+ endTurnEvent,
22405
+ playAgainEvent,
22406
+ gameEndEvent,
22407
+ className
22408
+ }) {
22409
+ const resolved = isEntityRow(entity) ? entity : void 0;
22410
+ return /* @__PURE__ */ jsxs(
22411
+ Box,
22412
+ {
22413
+ display: "flex",
22414
+ fullHeight: true,
22415
+ className: cn("card-battler-template flex-col", className),
22416
+ children: [
22417
+ /* @__PURE__ */ jsx(
22418
+ HStack,
22419
+ {
22420
+ gap: "sm",
22421
+ align: "center",
22422
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
22423
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
22424
+ }
22425
+ ),
22426
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
22427
+ CardBattlerBoard,
22428
+ {
22429
+ entity: resolved,
22430
+ deck,
22431
+ hand,
22432
+ board,
22433
+ mana,
22434
+ maxMana,
22435
+ turn,
22436
+ result,
22437
+ assetManifest,
22438
+ playCardEvent,
22439
+ endTurnEvent,
22440
+ playAgainEvent,
22441
+ gameEndEvent,
22442
+ className: "h-full"
22443
+ }
22444
+ ) })
22445
+ ]
22446
+ }
22447
+ );
22448
+ }
22449
+ var init_CardBattlerTemplate = __esm({
22450
+ "components/game/templates/CardBattlerTemplate.tsx"() {
22451
+ init_cn();
22452
+ init_Box();
22453
+ init_Stack();
22454
+ init_Typography();
22455
+ init_CardBattlerBoard();
22456
+ CardBattlerTemplate.displayName = "CardBattlerTemplate";
22457
+ }
22458
+ });
22077
22459
 
22078
22460
  // lib/getNestedValue.ts
22079
22461
  function getNestedValue(obj, path) {
@@ -23856,6 +24238,315 @@ var init_ChartLegend = __esm({
23856
24238
  ChartLegend.displayName = "ChartLegend";
23857
24239
  }
23858
24240
  });
24241
+ function resolveManifestUrl2(manifest, relative) {
24242
+ if (relative == null) return void 0;
24243
+ if (/^https?:\/\//.test(relative)) return relative;
24244
+ const base = manifest?.baseUrl;
24245
+ if (base == null) return relative;
24246
+ const cleanBase = base.replace(/\/$/, "");
24247
+ const cleanRel = relative.replace(/^\//, "");
24248
+ return `${cleanBase}/${cleanRel}`;
24249
+ }
24250
+ function buildDefaultCBTiles() {
24251
+ const tiles = [];
24252
+ for (let y = 0; y < CB_GRID_H; y++) {
24253
+ for (let x = 0; x < CB_GRID_W; x++) {
24254
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
24255
+ const terrainKey = ["grass", "stone", "dirt"][variant];
24256
+ tiles.push({ x, y, terrain: terrainKey, passable: true });
24257
+ }
24258
+ }
24259
+ return tiles;
24260
+ }
24261
+ function tilesToIso(tiles, manifest) {
24262
+ return tiles.map((t) => {
24263
+ const key = t.terrain ?? "grass";
24264
+ const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
24265
+ return {
24266
+ x: t.x,
24267
+ y: t.y,
24268
+ terrain: t.terrain,
24269
+ terrainSprite: sprite,
24270
+ passable: t.passable
24271
+ };
24272
+ });
24273
+ }
24274
+ function buildingsToFeatures(buildings, manifest) {
24275
+ return buildings.map((b) => ({
24276
+ id: b.id,
24277
+ x: b.x,
24278
+ y: b.y,
24279
+ type: b.type,
24280
+ sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
24281
+ }));
24282
+ }
24283
+ function CityBuilderBoard({
24284
+ entity,
24285
+ tiles: propTiles,
24286
+ buildings: propBuildings,
24287
+ assetManifest: propAssetManifest,
24288
+ buildTypes: propBuildTypes,
24289
+ pendingBuildType: propPendingBuildType,
24290
+ gold: propGold,
24291
+ wood: propWood,
24292
+ population: propPopulation,
24293
+ result: propResult,
24294
+ scale = 0.3,
24295
+ unitScale = 0.6,
24296
+ spriteHeightRatio = 1.5,
24297
+ spriteMaxWidthRatio = 0.7,
24298
+ selectBuildTypeEvent,
24299
+ placeBuildingEvent,
24300
+ gameEndEvent,
24301
+ className
24302
+ }) {
24303
+ const board = boardEntity(entity) ?? {};
24304
+ const eventBus = useEventBus();
24305
+ const { t } = useTranslate();
24306
+ const assetManifest = propAssetManifest ?? board.assetManifest;
24307
+ const entityTiles = useMemo(
24308
+ () => rows(board.tiles).map((r2) => ({
24309
+ x: num(r2.x),
24310
+ y: num(r2.y),
24311
+ terrain: r2.terrain == null ? void 0 : str(r2.terrain),
24312
+ terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
24313
+ passable: r2.passable !== false
24314
+ })),
24315
+ [board.tiles]
24316
+ );
24317
+ const rawTiles = propTiles ?? entityTiles;
24318
+ const tiles = rawTiles.length >= CB_GRID_W * CB_GRID_H ? rawTiles : DEFAULT_CB_TILES;
24319
+ const entityBuildings = useMemo(
24320
+ () => rows(board.buildings).map((r2) => ({
24321
+ id: str(r2.id),
24322
+ x: num(r2.x),
24323
+ y: num(r2.y),
24324
+ type: str(r2.type)
24325
+ })),
24326
+ [board.buildings]
24327
+ );
24328
+ const buildings = propBuildings ?? entityBuildings;
24329
+ const buildTypes = propBuildTypes ?? DEFAULT_BUILD_TYPES;
24330
+ const gold = propGold ?? num(board.gold, 100);
24331
+ const wood = propWood ?? num(board.wood, 80);
24332
+ const population = propPopulation ?? num(board.population, 0);
24333
+ const pendingBuildType = propPendingBuildType ?? (str(board.pendingBuildType) || buildTypes[0]?.type || "");
24334
+ const result = propResult ?? (str(board.result) || "none");
24335
+ const [hoveredTile, setHoveredTile] = useState(null);
24336
+ const emittedGameEnd = useRef(false);
24337
+ if (result !== "none" && !emittedGameEnd.current) {
24338
+ emittedGameEnd.current = true;
24339
+ if (gameEndEvent) {
24340
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
24341
+ }
24342
+ }
24343
+ if (result === "none") {
24344
+ emittedGameEnd.current = false;
24345
+ }
24346
+ const pendingCost = useMemo(
24347
+ () => buildTypes.find((b) => b.type === pendingBuildType)?.cost ?? 0,
24348
+ [buildTypes, pendingBuildType]
24349
+ );
24350
+ const buildingPositions = useMemo(
24351
+ () => new Set(buildings.map((b) => `${b.x},${b.y}`)),
24352
+ [buildings]
24353
+ );
24354
+ const validMoves = useMemo(() => {
24355
+ if (result !== "none" || gold < pendingCost) return [];
24356
+ return tiles.filter(
24357
+ (t2) => t2.passable !== false && !buildingPositions.has(`${t2.x},${t2.y}`)
24358
+ ).map((t2) => ({ x: t2.x, y: t2.y }));
24359
+ }, [tiles, buildingPositions, result, gold, pendingCost]);
24360
+ const isoTiles = useMemo(() => tilesToIso(tiles, assetManifest), [tiles, assetManifest]);
24361
+ const buildingFeatures = useMemo(() => buildingsToFeatures(buildings, assetManifest), [buildings, assetManifest]);
24362
+ const handleTileClick = useCallback((x, y) => {
24363
+ if (result !== "none") return;
24364
+ if (buildingPositions.has(`${x},${y}`)) return;
24365
+ if (gold < pendingCost) return;
24366
+ if (placeBuildingEvent) {
24367
+ eventBus.emit(`UI:${placeBuildingEvent}`, { x, y });
24368
+ }
24369
+ }, [result, buildingPositions, gold, pendingCost, placeBuildingEvent, eventBus]);
24370
+ const handleSelectBuildType = useCallback((buildType) => {
24371
+ if (selectBuildTypeEvent) {
24372
+ eventBus.emit(`UI:${selectBuildTypeEvent}`, { buildType });
24373
+ }
24374
+ }, [selectBuildTypeEvent, eventBus]);
24375
+ const canBuild = gold >= pendingCost && result === "none";
24376
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("city-builder-board relative min-h-[600px] bg-background", className), gap: "none", children: [
24377
+ /* @__PURE__ */ jsxs(
24378
+ HStack,
24379
+ {
24380
+ className: "px-4 py-2 border-b border-border bg-surface",
24381
+ gap: "lg",
24382
+ align: "center",
24383
+ children: [
24384
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
24385
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.gold") ?? "Gold" }),
24386
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
24387
+ ] }),
24388
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
24389
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.wood") ?? "Wood" }),
24390
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-success", children: wood })
24391
+ ] }),
24392
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
24393
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.population") ?? "Population" }),
24394
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: population })
24395
+ ] }),
24396
+ /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", className: "ml-auto", children: buildTypes.map((b) => /* @__PURE__ */ jsxs(
24397
+ Button,
24398
+ {
24399
+ variant: b.type === pendingBuildType ? "primary" : "secondary",
24400
+ size: "sm",
24401
+ disabled: gold < b.cost || result !== "none",
24402
+ onClick: () => handleSelectBuildType(b.type),
24403
+ children: [
24404
+ b.label,
24405
+ " (",
24406
+ b.cost,
24407
+ ")"
24408
+ ]
24409
+ },
24410
+ b.type
24411
+ )) })
24412
+ ]
24413
+ }
24414
+ ),
24415
+ /* @__PURE__ */ jsxs(Box, { className: "relative flex-1", children: [
24416
+ /* @__PURE__ */ jsx(
24417
+ IsometricCanvas_default,
24418
+ {
24419
+ tiles: isoTiles,
24420
+ features: buildingFeatures,
24421
+ assetBaseUrl: assetManifest?.baseUrl,
24422
+ assetManifest,
24423
+ validMoves,
24424
+ hoveredTile,
24425
+ onTileClick: handleTileClick,
24426
+ onTileHover: (x, y) => setHoveredTile({ x, y }),
24427
+ onTileLeave: () => setHoveredTile(null),
24428
+ scale,
24429
+ unitScale,
24430
+ spriteHeightRatio,
24431
+ spriteMaxWidthRatio
24432
+ }
24433
+ ),
24434
+ 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)` }) })
24435
+ ] }),
24436
+ 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: [
24437
+ /* @__PURE__ */ jsx(
24438
+ Typography,
24439
+ {
24440
+ variant: "h2",
24441
+ className: cn(
24442
+ "text-4xl font-black tracking-widest uppercase",
24443
+ result === "won" ? "text-warning" : "text-error"
24444
+ ),
24445
+ children: result === "won" ? t("cb.victory") ?? "City Thrives!" : t("cb.defeat") ?? "City Collapsed!"
24446
+ }
24447
+ ),
24448
+ /* @__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." })
24449
+ ] }) })
24450
+ ] });
24451
+ }
24452
+ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
24453
+ var init_CityBuilderBoard = __esm({
24454
+ "components/game/organisms/CityBuilderBoard.tsx"() {
24455
+ "use client";
24456
+ init_cn();
24457
+ init_useEventBus();
24458
+ init_Box();
24459
+ init_Button();
24460
+ init_Typography();
24461
+ init_Stack();
24462
+ init_IsometricCanvas();
24463
+ init_boardEntity();
24464
+ CB_GRID_W = 12;
24465
+ CB_GRID_H = 12;
24466
+ DEFAULT_BUILD_TYPES = [
24467
+ { type: "house", label: "House", cost: 20 },
24468
+ { type: "farm", label: "Farm", cost: 15 },
24469
+ { type: "mine", label: "Mine", cost: 25 },
24470
+ { type: "barracks", label: "Barracks", cost: 40 }
24471
+ ];
24472
+ DEFAULT_CB_TILES = buildDefaultCBTiles();
24473
+ CityBuilderBoard.displayName = "CityBuilderBoard";
24474
+ }
24475
+ });
24476
+ function isEntityRow2(value) {
24477
+ return value != null && typeof value === "object" && !Array.isArray(value);
24478
+ }
24479
+ function CityBuilderTemplate({
24480
+ entity,
24481
+ title = "City Builder",
24482
+ tiles,
24483
+ buildings,
24484
+ buildTypes,
24485
+ pendingBuildType,
24486
+ assetManifest,
24487
+ gold,
24488
+ wood,
24489
+ population,
24490
+ result,
24491
+ scale,
24492
+ unitScale,
24493
+ selectBuildTypeEvent,
24494
+ placeBuildingEvent,
24495
+ gameEndEvent,
24496
+ className
24497
+ }) {
24498
+ const resolved = isEntityRow2(entity) ? entity : void 0;
24499
+ return /* @__PURE__ */ jsxs(
24500
+ Box,
24501
+ {
24502
+ display: "flex",
24503
+ fullHeight: true,
24504
+ className: cn("city-builder-template flex-col", className),
24505
+ children: [
24506
+ /* @__PURE__ */ jsx(
24507
+ HStack,
24508
+ {
24509
+ gap: "sm",
24510
+ align: "center",
24511
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
24512
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
24513
+ }
24514
+ ),
24515
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
24516
+ CityBuilderBoard,
24517
+ {
24518
+ entity: resolved,
24519
+ tiles,
24520
+ buildings,
24521
+ buildTypes,
24522
+ pendingBuildType,
24523
+ assetManifest,
24524
+ gold,
24525
+ wood,
24526
+ population,
24527
+ result,
24528
+ scale,
24529
+ unitScale,
24530
+ selectBuildTypeEvent,
24531
+ placeBuildingEvent,
24532
+ gameEndEvent,
24533
+ className: "h-full"
24534
+ }
24535
+ ) })
24536
+ ]
24537
+ }
24538
+ );
24539
+ }
24540
+ var init_CityBuilderTemplate = __esm({
24541
+ "components/game/templates/CityBuilderTemplate.tsx"() {
24542
+ init_cn();
24543
+ init_Box();
24544
+ init_Stack();
24545
+ init_Typography();
24546
+ init_CityBuilderBoard();
24547
+ CityBuilderTemplate.displayName = "CityBuilderTemplate";
24548
+ }
24549
+ });
23859
24550
  function ClassifierBoard({
23860
24551
  entity,
23861
24552
  completeEvent = "PUZZLE_COMPLETE",
@@ -24670,7 +25361,7 @@ function CraftingRecipe({
24670
25361
  className
24671
25362
  }) {
24672
25363
  const eventBus = useEventBus();
24673
- const handleCraft = React90.useCallback(() => {
25364
+ const handleCraft = React93.useCallback(() => {
24674
25365
  onCraft?.();
24675
25366
  if (craftEvent) {
24676
25367
  eventBus.emit(craftEvent, { output: output.label });
@@ -24687,7 +25378,7 @@ function CraftingRecipe({
24687
25378
  children: [
24688
25379
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
24689
25380
  const hasSufficient = ingredient.available >= ingredient.required;
24690
- return /* @__PURE__ */ jsxs(React90.Fragment, { children: [
25381
+ return /* @__PURE__ */ jsxs(React93.Fragment, { children: [
24691
25382
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
24692
25383
  ItemSlot,
24693
25384
  {
@@ -24759,8 +25450,8 @@ function DPad({
24759
25450
  }) {
24760
25451
  const eventBus = useEventBus();
24761
25452
  const sizes = sizeMap15[size];
24762
- const [activeDirections, setActiveDirections] = React90.useState(/* @__PURE__ */ new Set());
24763
- const handlePress = React90.useCallback(
25453
+ const [activeDirections, setActiveDirections] = React93.useState(/* @__PURE__ */ new Set());
25454
+ const handlePress = React93.useCallback(
24764
25455
  (direction) => {
24765
25456
  setActiveDirections((prev) => new Set(prev).add(direction));
24766
25457
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -24768,7 +25459,7 @@ function DPad({
24768
25459
  },
24769
25460
  [directionEvent, eventBus, onDirection]
24770
25461
  );
24771
- const handleRelease = React90.useCallback(
25462
+ const handleRelease = React93.useCallback(
24772
25463
  (direction) => {
24773
25464
  setActiveDirections((prev) => {
24774
25465
  const next = new Set(prev);
@@ -25575,8 +26266,8 @@ var init_Menu = __esm({
25575
26266
  "bottom-end": "bottom-start"
25576
26267
  };
25577
26268
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
25578
- const triggerChild = React90__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
25579
- const triggerElement = React90__default.cloneElement(
26269
+ const triggerChild = React93__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
26270
+ const triggerElement = React93__default.cloneElement(
25580
26271
  triggerChild,
25581
26272
  {
25582
26273
  ref: triggerRef,
@@ -25710,14 +26401,14 @@ function useDataDnd(args) {
25710
26401
  const isZone = Boolean(dragGroup || accepts || sortable);
25711
26402
  const enabled = isZone || Boolean(dndRoot);
25712
26403
  const eventBus = useEventBus();
25713
- const parentRoot = React90__default.useContext(RootCtx);
26404
+ const parentRoot = React93__default.useContext(RootCtx);
25714
26405
  const isRoot = enabled && parentRoot === null;
25715
- const zoneId = React90__default.useId();
26406
+ const zoneId = React93__default.useId();
25716
26407
  const ownGroup = dragGroup ?? accepts ?? zoneId;
25717
- const [optimisticOrders, setOptimisticOrders] = React90__default.useState(() => /* @__PURE__ */ new Map());
25718
- const optimisticOrdersRef = React90__default.useRef(optimisticOrders);
26408
+ const [optimisticOrders, setOptimisticOrders] = React93__default.useState(() => /* @__PURE__ */ new Map());
26409
+ const optimisticOrdersRef = React93__default.useRef(optimisticOrders);
25719
26410
  optimisticOrdersRef.current = optimisticOrders;
25720
- const clearOptimisticOrder = React90__default.useCallback((group) => {
26411
+ const clearOptimisticOrder = React93__default.useCallback((group) => {
25721
26412
  setOptimisticOrders((prev) => {
25722
26413
  if (!prev.has(group)) return prev;
25723
26414
  const next = new Map(prev);
@@ -25742,7 +26433,7 @@ function useDataDnd(args) {
25742
26433
  const raw = it[dndItemIdField];
25743
26434
  return String(raw ?? `__idx_${idx}`);
25744
26435
  }).join("|");
25745
- const itemIds = React90__default.useMemo(
26436
+ const itemIds = React93__default.useMemo(
25746
26437
  () => orderedItems.map((it, idx) => {
25747
26438
  const raw = it[dndItemIdField];
25748
26439
  return raw ?? `__idx_${idx}`;
@@ -25750,7 +26441,7 @@ function useDataDnd(args) {
25750
26441
  [itemIdsSignature]
25751
26442
  );
25752
26443
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
25753
- React90__default.useEffect(() => {
26444
+ React93__default.useEffect(() => {
25754
26445
  const root = isRoot ? null : parentRoot;
25755
26446
  if (root) {
25756
26447
  root.clearOptimisticOrder(ownGroup);
@@ -25758,20 +26449,20 @@ function useDataDnd(args) {
25758
26449
  clearOptimisticOrder(ownGroup);
25759
26450
  }
25760
26451
  }, [itemsContentSig, ownGroup]);
25761
- const zonesRef = React90__default.useRef(/* @__PURE__ */ new Map());
25762
- const registerZone = React90__default.useCallback((zoneId2, meta2) => {
26452
+ const zonesRef = React93__default.useRef(/* @__PURE__ */ new Map());
26453
+ const registerZone = React93__default.useCallback((zoneId2, meta2) => {
25763
26454
  zonesRef.current.set(zoneId2, meta2);
25764
26455
  }, []);
25765
- const unregisterZone = React90__default.useCallback((zoneId2) => {
26456
+ const unregisterZone = React93__default.useCallback((zoneId2) => {
25766
26457
  zonesRef.current.delete(zoneId2);
25767
26458
  }, []);
25768
- const [activeDrag, setActiveDrag] = React90__default.useState(null);
25769
- const [overZoneGroup, setOverZoneGroup] = React90__default.useState(null);
25770
- const meta = React90__default.useMemo(
26459
+ const [activeDrag, setActiveDrag] = React93__default.useState(null);
26460
+ const [overZoneGroup, setOverZoneGroup] = React93__default.useState(null);
26461
+ const meta = React93__default.useMemo(
25771
26462
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
25772
26463
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
25773
26464
  );
25774
- React90__default.useEffect(() => {
26465
+ React93__default.useEffect(() => {
25775
26466
  const target = isRoot ? null : parentRoot;
25776
26467
  if (!target) {
25777
26468
  zonesRef.current.set(zoneId, meta);
@@ -25790,7 +26481,7 @@ function useDataDnd(args) {
25790
26481
  }, [parentRoot, isRoot, zoneId, meta]);
25791
26482
  const sensors = useAlmadarDndSensors(true);
25792
26483
  const collisionDetection = almadarDndCollisionDetection;
25793
- const findZoneByItem = React90__default.useCallback(
26484
+ const findZoneByItem = React93__default.useCallback(
25794
26485
  (id) => {
25795
26486
  for (const z of zonesRef.current.values()) {
25796
26487
  if (z.itemIds.includes(id)) return z;
@@ -25799,7 +26490,7 @@ function useDataDnd(args) {
25799
26490
  },
25800
26491
  []
25801
26492
  );
25802
- React90__default.useCallback(
26493
+ React93__default.useCallback(
25803
26494
  (group) => {
25804
26495
  for (const z of zonesRef.current.values()) {
25805
26496
  if (z.group === group) return z;
@@ -25808,7 +26499,7 @@ function useDataDnd(args) {
25808
26499
  },
25809
26500
  []
25810
26501
  );
25811
- const handleDragEnd = React90__default.useCallback(
26502
+ const handleDragEnd = React93__default.useCallback(
25812
26503
  (event) => {
25813
26504
  const { active, over } = event;
25814
26505
  const activeIdStr = String(active.id);
@@ -25899,8 +26590,8 @@ function useDataDnd(args) {
25899
26590
  },
25900
26591
  [eventBus]
25901
26592
  );
25902
- const sortableData = React90__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
25903
- const SortableItem = React90__default.useCallback(
26593
+ const sortableData = React93__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
26594
+ const SortableItem = React93__default.useCallback(
25904
26595
  ({ id, children }) => {
25905
26596
  const {
25906
26597
  attributes,
@@ -25940,7 +26631,7 @@ function useDataDnd(args) {
25940
26631
  id: droppableId,
25941
26632
  data: sortableData
25942
26633
  });
25943
- const ctx = React90__default.useContext(RootCtx);
26634
+ const ctx = React93__default.useContext(RootCtx);
25944
26635
  const activeDrag2 = ctx?.activeDrag ?? null;
25945
26636
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
25946
26637
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -25955,7 +26646,7 @@ function useDataDnd(args) {
25955
26646
  showForeignPlaceholder,
25956
26647
  ctxAvailable: ctx != null
25957
26648
  });
25958
- React90__default.useEffect(() => {
26649
+ React93__default.useEffect(() => {
25959
26650
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
25960
26651
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
25961
26652
  return /* @__PURE__ */ jsx(
@@ -25969,11 +26660,11 @@ function useDataDnd(args) {
25969
26660
  }
25970
26661
  );
25971
26662
  };
25972
- const rootContextValue = React90__default.useMemo(
26663
+ const rootContextValue = React93__default.useMemo(
25973
26664
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
25974
26665
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
25975
26666
  );
25976
- const handleDragStart = React90__default.useCallback((event) => {
26667
+ const handleDragStart = React93__default.useCallback((event) => {
25977
26668
  const sourceZone = findZoneByItem(event.active.id);
25978
26669
  const rect = event.active.rect.current.initial;
25979
26670
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -25992,7 +26683,7 @@ function useDataDnd(args) {
25992
26683
  isRoot
25993
26684
  });
25994
26685
  }, [findZoneByItem, isRoot, zoneId]);
25995
- const handleDragOver = React90__default.useCallback((event) => {
26686
+ const handleDragOver = React93__default.useCallback((event) => {
25996
26687
  const { active, over } = event;
25997
26688
  const overData = over?.data?.current;
25998
26689
  const overGroup = overData?.dndGroup ?? null;
@@ -26062,7 +26753,7 @@ function useDataDnd(args) {
26062
26753
  return next;
26063
26754
  });
26064
26755
  }, []);
26065
- const handleDragCancel = React90__default.useCallback((event) => {
26756
+ const handleDragCancel = React93__default.useCallback((event) => {
26066
26757
  setActiveDrag(null);
26067
26758
  setOverZoneGroup(null);
26068
26759
  dndLog.warn("dragCancel", {
@@ -26070,12 +26761,12 @@ function useDataDnd(args) {
26070
26761
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
26071
26762
  });
26072
26763
  }, []);
26073
- const handleDragEndWithCleanup = React90__default.useCallback((event) => {
26764
+ const handleDragEndWithCleanup = React93__default.useCallback((event) => {
26074
26765
  handleDragEnd(event);
26075
26766
  setActiveDrag(null);
26076
26767
  setOverZoneGroup(null);
26077
26768
  }, [handleDragEnd]);
26078
- const wrapContainer = React90__default.useCallback(
26769
+ const wrapContainer = React93__default.useCallback(
26079
26770
  (children) => {
26080
26771
  if (!enabled) return children;
26081
26772
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -26129,7 +26820,7 @@ var init_useDataDnd = __esm({
26129
26820
  init_useAlmadarDndCollision();
26130
26821
  init_Box();
26131
26822
  dndLog = createLogger("almadar:ui:dnd");
26132
- RootCtx = React90__default.createContext(null);
26823
+ RootCtx = React93__default.createContext(null);
26133
26824
  }
26134
26825
  });
26135
26826
  function renderIconInput(icon, props) {
@@ -26655,7 +27346,7 @@ function DataList({
26655
27346
  }) {
26656
27347
  const eventBus = useEventBus();
26657
27348
  const { t } = useTranslate();
26658
- const [visibleCount, setVisibleCount] = React90__default.useState(pageSize || Infinity);
27349
+ const [visibleCount, setVisibleCount] = React93__default.useState(pageSize || Infinity);
26659
27350
  const fieldDefs = fields ?? columns ?? [];
26660
27351
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
26661
27352
  const dnd = useDataDnd({
@@ -26674,7 +27365,7 @@ function DataList({
26674
27365
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
26675
27366
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
26676
27367
  const hasRenderProp = typeof children === "function";
26677
- React90__default.useEffect(() => {
27368
+ React93__default.useEffect(() => {
26678
27369
  const renderItemTypeOf = typeof schemaRenderItem;
26679
27370
  const childrenTypeOf = typeof children;
26680
27371
  if (data.length > 0 && !hasRenderProp) {
@@ -26779,7 +27470,7 @@ function DataList({
26779
27470
  const items2 = data.map((item) => item);
26780
27471
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
26781
27472
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
26782
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
27473
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
26783
27474
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
26784
27475
  group.items.map((itemData, index) => {
26785
27476
  const id = itemData.id || `${gi}-${index}`;
@@ -26920,7 +27611,7 @@ function DataList({
26920
27611
  className
26921
27612
  ),
26922
27613
  children: [
26923
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
27614
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
26924
27615
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
26925
27616
  group.items.map(
26926
27617
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -27836,7 +28527,7 @@ var init_Grid = __esm({
27836
28527
  as: Component2 = "div"
27837
28528
  }) => {
27838
28529
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
27839
- return React90__default.createElement(
28530
+ return React93__default.createElement(
27840
28531
  Component2,
27841
28532
  {
27842
28533
  className: cn(
@@ -28024,8 +28715,8 @@ var init_Popover = __esm({
28024
28715
  onMouseEnter: handleOpen,
28025
28716
  onMouseLeave: handleClose
28026
28717
  };
28027
- const childElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28028
- const triggerElement = React90__default.cloneElement(
28718
+ const childElement = React93__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28719
+ const triggerElement = React93__default.cloneElement(
28029
28720
  childElement,
28030
28721
  {
28031
28722
  ref: triggerRef,
@@ -28615,8 +29306,8 @@ var init_Tooltip = __esm({
28615
29306
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
28616
29307
  };
28617
29308
  }, []);
28618
- const triggerElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28619
- const trigger = React90__default.cloneElement(triggerElement, {
29309
+ const triggerElement = React93__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29310
+ const trigger = React93__default.cloneElement(triggerElement, {
28620
29311
  ref: triggerRef,
28621
29312
  onMouseEnter: handleMouseEnter,
28622
29313
  onMouseLeave: handleMouseLeave,
@@ -28702,7 +29393,7 @@ var init_WizardProgress = __esm({
28702
29393
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
28703
29394
  const isActive = index === currentStep;
28704
29395
  const isCompleted = index < currentStep;
28705
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
29396
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
28706
29397
  /* @__PURE__ */ jsx(
28707
29398
  "button",
28708
29399
  {
@@ -29663,7 +30354,7 @@ var init_ProgressDots = __esm({
29663
30354
  }
29664
30355
  });
29665
30356
  function StatBadge({
29666
- assetUrl = DEFAULT_ASSET_URL12,
30357
+ assetUrl,
29667
30358
  label,
29668
30359
  value = 0,
29669
30360
  max,
@@ -29730,7 +30421,7 @@ function StatBadge({
29730
30421
  }
29731
30422
  );
29732
30423
  }
29733
- var sizeMap17, variantMap2, DEFAULT_ASSET_URL12;
30424
+ var sizeMap17, variantMap2;
29734
30425
  var init_StatBadge = __esm({
29735
30426
  "components/game/molecules/StatBadge.tsx"() {
29736
30427
  init_cn();
@@ -29749,7 +30440,6 @@ var init_StatBadge = __esm({
29749
30440
  warning: "bg-warning/15 border-warning/40 text-foreground",
29750
30441
  danger: "bg-error/15 border-error/40 text-foreground"
29751
30442
  };
29752
- DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
29753
30443
  StatBadge.displayName = "StatBadge";
29754
30444
  }
29755
30445
  });
@@ -29766,7 +30456,7 @@ function InventoryGrid({
29766
30456
  const eventBus = useEventBus();
29767
30457
  const slotCount = totalSlots ?? items.length;
29768
30458
  const emptySlotCount = Math.max(0, slotCount - items.length);
29769
- const handleSelect = React90.useCallback(
30459
+ const handleSelect = React93.useCallback(
29770
30460
  (id) => {
29771
30461
  onSelect?.(id);
29772
30462
  if (selectEvent) {
@@ -29997,35 +30687,37 @@ function GameCanvas2D({
29997
30687
  drawEvent,
29998
30688
  fps = 60,
29999
30689
  backgroundImage = "",
30000
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
30690
+ assetBaseUrl,
30001
30691
  className
30002
30692
  }) {
30003
- const canvasRef = React90.useRef(null);
30004
- const rafRef = React90.useRef(0);
30005
- const frameRef = React90.useRef(0);
30006
- const lastTimeRef = React90.useRef(0);
30007
- const imageCache = React90.useRef(/* @__PURE__ */ new Map());
30693
+ const canvasRef = React93.useRef(null);
30694
+ const rafRef = React93.useRef(0);
30695
+ const frameRef = React93.useRef(0);
30696
+ const lastTimeRef = React93.useRef(0);
30697
+ const imageCache = React93.useRef(/* @__PURE__ */ new Map());
30008
30698
  const emit = useEmitEvent();
30009
- const onDrawRef = React90.useRef(onDraw);
30699
+ const onDrawRef = React93.useRef(onDraw);
30010
30700
  onDrawRef.current = onDraw;
30011
- const onTickRef = React90.useRef(onTick);
30701
+ const onTickRef = React93.useRef(onTick);
30012
30702
  onTickRef.current = onTick;
30013
- const tickEventRef = React90.useRef(tickEvent);
30703
+ const tickEventRef = React93.useRef(tickEvent);
30014
30704
  tickEventRef.current = tickEvent;
30015
- const drawEventRef = React90.useRef(drawEvent);
30705
+ const drawEventRef = React93.useRef(drawEvent);
30016
30706
  drawEventRef.current = drawEvent;
30017
- const emitRef = React90.useRef(emit);
30707
+ const emitRef = React93.useRef(emit);
30018
30708
  emitRef.current = emit;
30019
- const assetBaseUrlRef = React90.useRef(assetBaseUrl);
30709
+ const assetBaseUrlRef = React93.useRef(assetBaseUrl);
30020
30710
  assetBaseUrlRef.current = assetBaseUrl;
30021
- const backgroundImageRef = React90.useRef(backgroundImage);
30711
+ const backgroundImageRef = React93.useRef(backgroundImage);
30022
30712
  backgroundImageRef.current = backgroundImage;
30023
- const widthRef = React90.useRef(width);
30713
+ const widthRef = React93.useRef(width);
30024
30714
  widthRef.current = width;
30025
- const heightRef = React90.useRef(height);
30715
+ const heightRef = React93.useRef(height);
30026
30716
  heightRef.current = height;
30027
- const loadImage = React90.useCallback((url) => {
30028
- const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
30717
+ const loadImage = React93.useCallback((url) => {
30718
+ const base = assetBaseUrlRef.current;
30719
+ if (!url.startsWith("http") && !base) return null;
30720
+ const fullUrl = url.startsWith("http") ? url : `${base}${url}`;
30029
30721
  const cached = imageCache.current.get(fullUrl);
30030
30722
  if (cached?.complete && cached.naturalWidth > 0) return cached;
30031
30723
  if (!cached) {
@@ -30036,7 +30728,7 @@ function GameCanvas2D({
30036
30728
  }
30037
30729
  return null;
30038
30730
  }, []);
30039
- React90.useEffect(() => {
30731
+ React93.useEffect(() => {
30040
30732
  const canvas = canvasRef.current;
30041
30733
  if (!canvas) return;
30042
30734
  const ctx = canvas.getContext("2d");
@@ -30348,7 +31040,7 @@ function TurnPanel({
30348
31040
  className
30349
31041
  }) {
30350
31042
  const eventBus = useEventBus();
30351
- const handleAction = React90.useCallback(
31043
+ const handleAction = React93.useCallback(
30352
31044
  (event) => {
30353
31045
  if (event) {
30354
31046
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -30406,7 +31098,7 @@ var init_TurnPanel = __esm({
30406
31098
  }
30407
31099
  });
30408
31100
  function EnemyPlate({
30409
- assetUrl = DEFAULT_ASSET_URL13,
31101
+ assetUrl,
30410
31102
  name = "Shadow Guard",
30411
31103
  health = 80,
30412
31104
  maxHealth = 100,
@@ -30490,7 +31182,7 @@ function EnemyPlate({
30490
31182
  }
30491
31183
  );
30492
31184
  }
30493
- var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL13;
31185
+ var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
30494
31186
  var init_EnemyPlate = __esm({
30495
31187
  "components/game/molecules/EnemyPlate.tsx"() {
30496
31188
  "use client";
@@ -30507,7 +31199,6 @@ var init_EnemyPlate = __esm({
30507
31199
  DEFAULT_ENEMY_EFFECTS = [
30508
31200
  { icon: "flame", label: "Burn", variant: "debuff" }
30509
31201
  ];
30510
- DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
30511
31202
  EnemyPlate.displayName = "EnemyPlate";
30512
31203
  }
30513
31204
  });
@@ -30517,7 +31208,7 @@ function UnitCommandBar({
30517
31208
  className
30518
31209
  }) {
30519
31210
  const eventBus = useEventBus();
30520
- const handleCommand = React90.useCallback(
31211
+ const handleCommand = React93.useCallback(
30521
31212
  (event) => {
30522
31213
  if (event) {
30523
31214
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -30658,6 +31349,9 @@ function DialogueBox({
30658
31349
  completeEvent,
30659
31350
  choiceEvent,
30660
31351
  advanceEvent,
31352
+ backgroundImage,
31353
+ portraitUrl,
31354
+ portraitScale = 1,
30661
31355
  className
30662
31356
  }) {
30663
31357
  const eventBus = useEventBus();
@@ -30773,64 +31467,98 @@ function DialogueBox({
30773
31467
  }
30774
31468
  }, [isTyping, skipTypewriter, dialogue.choices, selectedChoice, onChoice, onAdvance, choiceEvent, advanceEvent, eventBus]);
30775
31469
  const enabledChoices = dialogue.choices?.filter((c) => !c.disabled) ?? [];
30776
- return /* @__PURE__ */ jsx(
30777
- "div",
30778
- {
30779
- className: cn(
30780
- "fixed left-0 right-0 z-40",
30781
- position === "top" ? "top-0" : "bottom-0",
30782
- className
30783
- ),
30784
- onClick: handleClick,
30785
- onKeyDown: handleKeyDown,
30786
- tabIndex: 0,
30787
- role: "dialog",
30788
- "aria-label": "Dialogue",
30789
- 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: [
30790
- dialogue.portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-4 border-r border-border", children: /* @__PURE__ */ jsx(
31470
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
31471
+ backgroundImage && /* @__PURE__ */ jsx(
31472
+ "div",
31473
+ {
31474
+ className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
31475
+ style: { backgroundImage: `url(${backgroundImage})` },
31476
+ "aria-hidden": "true"
31477
+ }
31478
+ ),
31479
+ portraitUrl && /* @__PURE__ */ jsx(
31480
+ "div",
31481
+ {
31482
+ className: cn(
31483
+ "fixed left-1/2 -translate-x-1/2 z-30 pointer-events-none flex items-end",
31484
+ position === "top" ? "top-0" : "bottom-0"
31485
+ ),
31486
+ style: { height: `${60 * portraitScale}vh` },
31487
+ children: /* @__PURE__ */ jsx(
30791
31488
  "img",
30792
31489
  {
30793
- src: dialogue.portrait,
31490
+ src: portraitUrl,
30794
31491
  alt: dialogue.speaker,
30795
- className: "w-24 h-24 object-contain",
30796
- style: { imageRendering: "pixelated" }
31492
+ className: "h-full w-auto object-contain drop-shadow-2xl"
30797
31493
  }
30798
- ) }),
30799
- /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4", children: [
30800
- /* @__PURE__ */ jsx("div", { className: "text-warning font-bold mb-2", children: dialogue.speaker }),
30801
- /* @__PURE__ */ jsxs("div", { className: "text-[var(--color-foreground)] text-lg leading-relaxed min-h-[60px]", children: [
30802
- displayedText,
30803
- isTyping && /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "\u258C" })
30804
- ] }),
30805
- !isTyping && enabledChoices.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: enabledChoices.map((choice, index) => /* @__PURE__ */ jsxs(
30806
- "button",
31494
+ )
31495
+ }
31496
+ ),
31497
+ /* @__PURE__ */ jsx(
31498
+ "div",
31499
+ {
31500
+ className: cn(
31501
+ "fixed left-0 right-0 z-40",
31502
+ position === "top" ? "top-0" : "bottom-0",
31503
+ className
31504
+ ),
31505
+ onClick: handleClick,
31506
+ onKeyDown: handleKeyDown,
31507
+ tabIndex: 0,
31508
+ role: "dialog",
31509
+ "aria-label": "Dialogue",
31510
+ children: /* @__PURE__ */ jsx("div", { className: cn(
31511
+ "mx-4 my-4 border-2 rounded-container overflow-hidden",
31512
+ backgroundImage ? "bg-black/80 backdrop-blur-sm text-white border-white/20" : "bg-[var(--color-card)] bg-opacity-95 border-border"
31513
+ ), children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
31514
+ dialogue.portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-4 border-r border-border", children: /* @__PURE__ */ jsx(
31515
+ "img",
30807
31516
  {
30808
- type: "button",
30809
- className: cn(
30810
- "block w-full text-left px-4 py-2 rounded-interactive transition-colors",
30811
- "hover:bg-[var(--color-surface,#374151)] focus:outline-none focus:ring-2 focus:ring-warning",
30812
- selectedChoice === index ? "bg-[var(--color-surface,#374151)] text-warning" : "bg-[var(--color-card)] text-[var(--color-foreground)]"
30813
- ),
30814
- onClick: (e) => {
30815
- e.stopPropagation();
30816
- if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
30817
- onChoice?.(choice);
31517
+ src: dialogue.portrait,
31518
+ alt: dialogue.speaker,
31519
+ className: "w-24 h-24 object-contain",
31520
+ style: { imageRendering: "pixelated" }
31521
+ }
31522
+ ) }),
31523
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4", children: [
31524
+ /* @__PURE__ */ jsx("div", { className: "text-warning font-bold mb-2", children: dialogue.speaker }),
31525
+ /* @__PURE__ */ jsxs("div", { className: cn(
31526
+ "text-lg leading-relaxed min-h-[60px]",
31527
+ backgroundImage ? "text-white" : "text-[var(--color-foreground)]"
31528
+ ), children: [
31529
+ displayedText,
31530
+ isTyping && /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "\u258C" })
31531
+ ] }),
31532
+ !isTyping && enabledChoices.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: enabledChoices.map((choice, index) => /* @__PURE__ */ jsxs(
31533
+ "button",
31534
+ {
31535
+ type: "button",
31536
+ className: cn(
31537
+ "block w-full text-left px-4 py-2 rounded-interactive transition-colors",
31538
+ "hover:bg-[var(--color-surface,#374151)] focus:outline-none focus:ring-2 focus:ring-warning",
31539
+ 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)]"
31540
+ ),
31541
+ onClick: (e) => {
31542
+ e.stopPropagation();
31543
+ if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
31544
+ onChoice?.(choice);
31545
+ },
31546
+ children: [
31547
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground mr-2", children: [
31548
+ index + 1,
31549
+ "."
31550
+ ] }),
31551
+ choice.text
31552
+ ]
30818
31553
  },
30819
- children: [
30820
- /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground mr-2", children: [
30821
- index + 1,
30822
- "."
30823
- ] }),
30824
- choice.text
30825
- ]
30826
- },
30827
- index
30828
- )) }),
30829
- !isTyping && !dialogue.choices?.length && /* @__PURE__ */ jsx("div", { className: "mt-4 text-muted-foreground text-sm animate-pulse", children: "Press SPACE or click to continue..." })
30830
- ] })
30831
- ] }) })
30832
- }
30833
- );
31554
+ index
31555
+ )) }),
31556
+ !isTyping && !dialogue.choices?.length && /* @__PURE__ */ jsx("div", { className: "mt-4 text-muted-foreground text-sm animate-pulse", children: "Press SPACE or click to continue..." })
31557
+ ] })
31558
+ ] }) })
31559
+ }
31560
+ )
31561
+ ] });
30834
31562
  }
30835
31563
  var DEFAULT_DIALOGUE;
30836
31564
  var init_DialogueBox = __esm({
@@ -31031,7 +31759,7 @@ function GameMenu({
31031
31759
  } catch {
31032
31760
  }
31033
31761
  const eventBus = eventBusProp || eventBusFromHook;
31034
- const handleOptionClick = React90.useCallback(
31762
+ const handleOptionClick = React93.useCallback(
31035
31763
  (option) => {
31036
31764
  if (option.event && eventBus) {
31037
31765
  eventBus.emit(`UI:${option.event}`, { option });
@@ -31150,7 +31878,7 @@ function GameOverScreen({
31150
31878
  } catch {
31151
31879
  }
31152
31880
  const eventBus = eventBusProp || eventBusFromHook;
31153
- const handleActionClick = React90.useCallback(
31881
+ const handleActionClick = React93.useCallback(
31154
31882
  (action) => {
31155
31883
  if (action.event && eventBus) {
31156
31884
  eventBus.emit(`UI:${action.event}`, { action });
@@ -31357,10 +32085,10 @@ function PlatformerCanvas({
31357
32085
  canvasHeight = 400,
31358
32086
  followCamera = true,
31359
32087
  bgColor = "#5c94fc",
31360
- playerSprite = "https://almadar-kflow-assets.web.app/shared/platformer/characters/platformChar_idle.png",
32088
+ playerSprite,
31361
32089
  tileSprites,
31362
32090
  backgroundImage = "",
31363
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/platformer/",
32091
+ assetBaseUrl,
31364
32092
  leftEvent = "MOVE_LEFT",
31365
32093
  rightEvent = "MOVE_RIGHT",
31366
32094
  jumpEvent = "JUMP",
@@ -31374,6 +32102,7 @@ function PlatformerCanvas({
31374
32102
  const imageCache = useRef(/* @__PURE__ */ new Map());
31375
32103
  const [loadedImages, setLoadedImages] = useState(/* @__PURE__ */ new Set());
31376
32104
  const loadImage = useCallback((url) => {
32105
+ if (!url.startsWith("http") && !assetBaseUrl) return null;
31377
32106
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
31378
32107
  const cached = imageCache.current.get(fullUrl);
31379
32108
  if (cached?.complete && cached.naturalWidth > 0) {
@@ -32072,13 +32801,13 @@ var init_MapView = __esm({
32072
32801
  shadowSize: [41, 41]
32073
32802
  });
32074
32803
  L.Marker.prototype.options.icon = defaultIcon;
32075
- const { useEffect: useEffect86, useRef: useRef77, useCallback: useCallback125, useState: useState121 } = React90__default;
32804
+ const { useEffect: useEffect87, useRef: useRef80, useCallback: useCallback130, useState: useState122 } = React93__default;
32076
32805
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
32077
32806
  const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
32078
32807
  function MapUpdater({ centerLat, centerLng, zoom }) {
32079
32808
  const map = useMap();
32080
- const prevRef = useRef77({ centerLat, centerLng, zoom });
32081
- useEffect86(() => {
32809
+ const prevRef = useRef80({ centerLat, centerLng, zoom });
32810
+ useEffect87(() => {
32082
32811
  const prev = prevRef.current;
32083
32812
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
32084
32813
  map.setView([centerLat, centerLng], zoom);
@@ -32089,7 +32818,7 @@ var init_MapView = __esm({
32089
32818
  }
32090
32819
  function MapClickHandler({ onMapClick }) {
32091
32820
  const map = useMap();
32092
- useEffect86(() => {
32821
+ useEffect87(() => {
32093
32822
  if (!onMapClick) return;
32094
32823
  const handler = (e) => {
32095
32824
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32117,8 +32846,8 @@ var init_MapView = __esm({
32117
32846
  showAttribution = true
32118
32847
  }) {
32119
32848
  const eventBus = useEventBus4();
32120
- const [clickedPosition, setClickedPosition] = useState121(null);
32121
- const handleMapClick = useCallback125((lat, lng) => {
32849
+ const [clickedPosition, setClickedPosition] = useState122(null);
32850
+ const handleMapClick = useCallback130((lat, lng) => {
32122
32851
  if (showClickedPin) {
32123
32852
  setClickedPosition({ lat, lng });
32124
32853
  }
@@ -32127,7 +32856,7 @@ var init_MapView = __esm({
32127
32856
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
32128
32857
  }
32129
32858
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
32130
- const handleMarkerClick = useCallback125((marker) => {
32859
+ const handleMarkerClick = useCallback130((marker) => {
32131
32860
  onMarkerClick?.(marker);
32132
32861
  if (markerClickEvent) {
32133
32862
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -32978,8 +33707,8 @@ function TableView({
32978
33707
  }) {
32979
33708
  const eventBus = useEventBus();
32980
33709
  const { t } = useTranslate();
32981
- const [visibleCount, setVisibleCount] = React90__default.useState(pageSize > 0 ? pageSize : Infinity);
32982
- const [localSelected, setLocalSelected] = React90__default.useState(/* @__PURE__ */ new Set());
33710
+ const [visibleCount, setVisibleCount] = React93__default.useState(pageSize > 0 ? pageSize : Infinity);
33711
+ const [localSelected, setLocalSelected] = React93__default.useState(/* @__PURE__ */ new Set());
32983
33712
  const colDefs = columns ?? fields ?? [];
32984
33713
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
32985
33714
  const dnd = useDataDnd({
@@ -33174,12 +33903,12 @@ function TableView({
33174
33903
  ]
33175
33904
  }
33176
33905
  );
33177
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React90__default.Fragment, { children: rowInner }, id);
33906
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React93__default.Fragment, { children: rowInner }, id);
33178
33907
  };
33179
33908
  const items = data.map((row) => row);
33180
33909
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
33181
33910
  let runningIndex = 0;
33182
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
33911
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
33183
33912
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
33184
33913
  group.items.map((row) => renderRow(row, runningIndex++))
33185
33914
  ] }, gi)) });
@@ -34536,7 +35265,7 @@ var init_StepFlow = __esm({
34536
35265
  className
34537
35266
  }) => {
34538
35267
  if (orientation === "vertical") {
34539
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React90__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
35268
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React93__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
34540
35269
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
34541
35270
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34542
35271
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -34547,7 +35276,7 @@ var init_StepFlow = __esm({
34547
35276
  ] })
34548
35277
  ] }) }, index)) });
34549
35278
  }
34550
- 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(React90__default.Fragment, { children: [
35279
+ 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(React93__default.Fragment, { children: [
34551
35280
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
34552
35281
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34553
35282
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -35532,7 +36261,7 @@ var init_LikertScale = __esm({
35532
36261
  md: "text-base",
35533
36262
  lg: "text-lg"
35534
36263
  };
35535
- LikertScale = React90__default.forwardRef(
36264
+ LikertScale = React93__default.forwardRef(
35536
36265
  ({
35537
36266
  question,
35538
36267
  options = DEFAULT_LIKERT_OPTIONS,
@@ -35544,7 +36273,7 @@ var init_LikertScale = __esm({
35544
36273
  variant = "radios",
35545
36274
  className
35546
36275
  }, ref) => {
35547
- const groupId = React90__default.useId();
36276
+ const groupId = React93__default.useId();
35548
36277
  const eventBus = useEventBus();
35549
36278
  const handleSelect = useCallback(
35550
36279
  (next) => {
@@ -37826,7 +38555,7 @@ var init_DocBreadcrumb = __esm({
37826
38555
  "aria-label": t("aria.breadcrumb"),
37827
38556
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
37828
38557
  const isLast = idx === items.length - 1;
37829
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
38558
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
37830
38559
  idx > 0 && /* @__PURE__ */ jsx(
37831
38560
  Icon,
37832
38561
  {
@@ -38490,7 +39219,7 @@ var init_PageHeader = __esm({
38490
39219
  info: "bg-info/10 text-info"
38491
39220
  };
38492
39221
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
38493
- 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(React90__default.Fragment, { children: [
39222
+ 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(React93__default.Fragment, { children: [
38494
39223
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
38495
39224
  crumb.href ? /* @__PURE__ */ jsx(
38496
39225
  "a",
@@ -39172,8 +39901,8 @@ var init_WizardContainer = __esm({
39172
39901
  return void 0;
39173
39902
  if (typeof controlledStep === "number") return controlledStep;
39174
39903
  if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
39175
- const num2 = Number(controlledStep);
39176
- return isNaN(num2) ? void 0 : num2;
39904
+ const num3 = Number(controlledStep);
39905
+ return isNaN(num3) ? void 0 : num3;
39177
39906
  })();
39178
39907
  const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
39179
39908
  const totalSteps = steps.length;
@@ -39219,7 +39948,7 @@ var init_WizardContainer = __esm({
39219
39948
  const isCompleted = index < currentStep;
39220
39949
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
39221
39950
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
39222
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
39951
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
39223
39952
  /* @__PURE__ */ jsx(
39224
39953
  Button,
39225
39954
  {
@@ -40151,6 +40880,8 @@ var init_GraphCanvas = __esm({
40151
40880
  selectedNodeId,
40152
40881
  repulsion = 800,
40153
40882
  linkDistance = 100,
40883
+ nodeSpacing = 28,
40884
+ linkOpacity = 0.18,
40154
40885
  layout = "force",
40155
40886
  entity,
40156
40887
  isLoading = false,
@@ -40310,6 +41041,25 @@ var init_GraphCanvas = __esm({
40310
41041
  node.x = Math.max(30, Math.min(w - 30, node.x));
40311
41042
  node.y = Math.max(30, Math.min(h - 30, node.y));
40312
41043
  }
41044
+ for (let i = 0; i < nodes.length; i++) {
41045
+ for (let j = i + 1; j < nodes.length; j++) {
41046
+ const a = nodes[i];
41047
+ const b = nodes[j];
41048
+ const dx = b.x - a.x;
41049
+ const dy = b.y - a.y;
41050
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
41051
+ const minDist = (a.size || 8) + (b.size || 8) + nodeSpacing;
41052
+ if (dist < minDist) {
41053
+ const push2 = (minDist - dist) / 2;
41054
+ const ux = dx / dist;
41055
+ const uy = dy / dist;
41056
+ a.x = Math.max(30, Math.min(w - 30, a.x - ux * push2));
41057
+ a.y = Math.max(30, Math.min(h - 30, a.y - uy * push2));
41058
+ b.x = Math.max(30, Math.min(w - 30, b.x + ux * push2));
41059
+ b.y = Math.max(30, Math.min(h - 30, b.y + uy * push2));
41060
+ }
41061
+ }
41062
+ }
40313
41063
  iterations++;
40314
41064
  forceUpdate((n) => n + 1);
40315
41065
  if (iterations < maxIterations) {
@@ -40323,7 +41073,7 @@ var init_GraphCanvas = __esm({
40323
41073
  return () => {
40324
41074
  cancelAnimationFrame(animRef.current);
40325
41075
  };
40326
- }, [propNodes, propEdges, layout, repulsion, linkDistance, logicalW, height]);
41076
+ }, [propNodes, propEdges, layout, repulsion, linkDistance, nodeSpacing, logicalW, height]);
40327
41077
  useEffect(() => {
40328
41078
  const canvas = canvasRef.current;
40329
41079
  if (!canvas) return;
@@ -40352,11 +41102,11 @@ var init_GraphCanvas = __esm({
40352
41102
  const target = nodes.find((n) => n.id === edge.target);
40353
41103
  if (!source || !target) continue;
40354
41104
  const incident = !!hoveredNode && (edge.source === hoveredNode || edge.target === hoveredNode);
40355
- ctx.globalAlpha = hoveredNode ? incident ? 1 : 0.12 : 1;
41105
+ ctx.globalAlpha = hoveredNode ? incident ? 1 : 0.05 : linkOpacity;
40356
41106
  ctx.beginPath();
40357
41107
  ctx.moveTo(source.x, source.y);
40358
41108
  ctx.lineTo(target.x, target.y);
40359
- ctx.strokeStyle = incident ? accentColor : edge.color || "#88888866";
41109
+ ctx.strokeStyle = incident ? accentColor : edge.color || "#888888";
40360
41110
  ctx.lineWidth = incident ? 2 : edge.weight ? Math.max(1, edge.weight) : 1;
40361
41111
  ctx.stroke();
40362
41112
  if (edge.label && showLabels) {
@@ -41720,7 +42470,7 @@ var init_DetailPanel = __esm({
41720
42470
  }
41721
42471
  });
41722
42472
  function extractTitle(children) {
41723
- if (!React90__default.isValidElement(children)) return void 0;
42473
+ if (!React93__default.isValidElement(children)) return void 0;
41724
42474
  const props = children.props;
41725
42475
  if (typeof props.title === "string") {
41726
42476
  return props.title;
@@ -41775,7 +42525,7 @@ function LinearView({
41775
42525
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
41776
42526
  const isDone = i < currentIdx;
41777
42527
  const isCurrent = i === currentIdx;
41778
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
42528
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
41779
42529
  i > 0 && /* @__PURE__ */ jsx(
41780
42530
  Typography,
41781
42531
  {
@@ -42725,12 +43475,12 @@ var init_Form = __esm({
42725
43475
  const isSchemaEntity = isOrbitalEntitySchema(entity);
42726
43476
  const resolvedEntity = isSchemaEntity ? entity : void 0;
42727
43477
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
42728
- const normalizedInitialData = React90__default.useMemo(() => {
43478
+ const normalizedInitialData = React93__default.useMemo(() => {
42729
43479
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
42730
43480
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
42731
43481
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
42732
43482
  }, [entity, initialData]);
42733
- const entityDerivedFields = React90__default.useMemo(() => {
43483
+ const entityDerivedFields = React93__default.useMemo(() => {
42734
43484
  if (fields && fields.length > 0) return void 0;
42735
43485
  if (!resolvedEntity) return void 0;
42736
43486
  return resolvedEntity.fields.map(
@@ -42750,16 +43500,16 @@ var init_Form = __esm({
42750
43500
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
42751
43501
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
42752
43502
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
42753
- const [formData, setFormData] = React90__default.useState(
43503
+ const [formData, setFormData] = React93__default.useState(
42754
43504
  normalizedInitialData
42755
43505
  );
42756
- const [collapsedSections, setCollapsedSections] = React90__default.useState(
43506
+ const [collapsedSections, setCollapsedSections] = React93__default.useState(
42757
43507
  /* @__PURE__ */ new Set()
42758
43508
  );
42759
- const [submitError, setSubmitError] = React90__default.useState(null);
42760
- const formRef = React90__default.useRef(null);
43509
+ const [submitError, setSubmitError] = React93__default.useState(null);
43510
+ const formRef = React93__default.useRef(null);
42761
43511
  const formMode = props.mode;
42762
- const mountedRef = React90__default.useRef(false);
43512
+ const mountedRef = React93__default.useRef(false);
42763
43513
  if (!mountedRef.current) {
42764
43514
  mountedRef.current = true;
42765
43515
  debug("forms", "mount", {
@@ -42772,7 +43522,7 @@ var init_Form = __esm({
42772
43522
  });
42773
43523
  }
42774
43524
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
42775
- const evalContext = React90__default.useMemo(
43525
+ const evalContext = React93__default.useMemo(
42776
43526
  () => ({
42777
43527
  formValues: formData,
42778
43528
  globalVariables: externalContext?.globalVariables ?? {},
@@ -42781,7 +43531,7 @@ var init_Form = __esm({
42781
43531
  }),
42782
43532
  [formData, externalContext]
42783
43533
  );
42784
- React90__default.useEffect(() => {
43534
+ React93__default.useEffect(() => {
42785
43535
  debug("forms", "initialData-sync", {
42786
43536
  mode: formMode,
42787
43537
  normalizedInitialData,
@@ -42792,7 +43542,7 @@ var init_Form = __esm({
42792
43542
  setFormData(normalizedInitialData);
42793
43543
  }
42794
43544
  }, [normalizedInitialData]);
42795
- const processCalculations = React90__default.useCallback(
43545
+ const processCalculations = React93__default.useCallback(
42796
43546
  (changedFieldId, newFormData) => {
42797
43547
  if (!hiddenCalculations.length) return;
42798
43548
  const context = {
@@ -42817,7 +43567,7 @@ var init_Form = __esm({
42817
43567
  },
42818
43568
  [hiddenCalculations, externalContext, eventBus]
42819
43569
  );
42820
- const checkViolations = React90__default.useCallback(
43570
+ const checkViolations = React93__default.useCallback(
42821
43571
  (changedFieldId, newFormData) => {
42822
43572
  if (!violationTriggers.length) return;
42823
43573
  const context = {
@@ -42855,7 +43605,7 @@ var init_Form = __esm({
42855
43605
  processCalculations(name, newFormData);
42856
43606
  checkViolations(name, newFormData);
42857
43607
  };
42858
- const isFieldVisible = React90__default.useCallback(
43608
+ const isFieldVisible = React93__default.useCallback(
42859
43609
  (fieldName) => {
42860
43610
  const condition = conditionalFields[fieldName];
42861
43611
  if (!condition) return true;
@@ -42863,7 +43613,7 @@ var init_Form = __esm({
42863
43613
  },
42864
43614
  [conditionalFields, evalContext]
42865
43615
  );
42866
- const isSectionVisible = React90__default.useCallback(
43616
+ const isSectionVisible = React93__default.useCallback(
42867
43617
  (section) => {
42868
43618
  if (!section.condition) return true;
42869
43619
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -42939,7 +43689,7 @@ var init_Form = __esm({
42939
43689
  eventBus.emit(`UI:${onCancel}`);
42940
43690
  }
42941
43691
  };
42942
- const renderField = React90__default.useCallback(
43692
+ const renderField = React93__default.useCallback(
42943
43693
  (field) => {
42944
43694
  const fieldName = field.name || field.field;
42945
43695
  if (!fieldName) return null;
@@ -42960,7 +43710,7 @@ var init_Form = __esm({
42960
43710
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
42961
43711
  );
42962
43712
  const effectiveFields = entityDerivedFields ?? fields;
42963
- const normalizedFields = React90__default.useMemo(() => {
43713
+ const normalizedFields = React93__default.useMemo(() => {
42964
43714
  if (!effectiveFields || effectiveFields.length === 0) return [];
42965
43715
  return effectiveFields.map((field) => {
42966
43716
  if (typeof field === "string") {
@@ -42983,7 +43733,7 @@ var init_Form = __esm({
42983
43733
  return field;
42984
43734
  });
42985
43735
  }, [effectiveFields, resolvedEntity]);
42986
- const schemaFields = React90__default.useMemo(() => {
43736
+ const schemaFields = React93__default.useMemo(() => {
42987
43737
  if (normalizedFields.length === 0) return null;
42988
43738
  if (isDebugEnabled()) {
42989
43739
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -42993,7 +43743,7 @@ var init_Form = __esm({
42993
43743
  }
42994
43744
  return normalizedFields.map(renderField).filter(Boolean);
42995
43745
  }, [normalizedFields, renderField, entityName, conditionalFields]);
42996
- const sectionElements = React90__default.useMemo(() => {
43746
+ const sectionElements = React93__default.useMemo(() => {
42997
43747
  if (!sections || sections.length === 0) return null;
42998
43748
  return sections.map((section) => {
42999
43749
  if (!isSectionVisible(section)) {
@@ -44313,12 +45063,18 @@ function ModelLoader({
44313
45063
  });
44314
45064
  return cloned;
44315
45065
  }, [loadedModel, castShadow, receiveShadow]);
45066
+ const normFactor = useMemo(() => {
45067
+ if (!model) return 1;
45068
+ const box = new THREE3.Box3().setFromObject(model);
45069
+ const size = new THREE3.Vector3();
45070
+ box.getSize(size);
45071
+ const maxDim = Math.max(size.x, size.y, size.z);
45072
+ return maxDim > 0 && Number.isFinite(maxDim) ? 1 / maxDim : 1;
45073
+ }, [model]);
44316
45074
  const scaleArray = useMemo(() => {
44317
- if (typeof scale === "number") {
44318
- return [scale, scale, scale];
44319
- }
44320
- return scale;
44321
- }, [scale]);
45075
+ const base = typeof scale === "number" ? [scale, scale, scale] : scale;
45076
+ return [base[0] * normFactor, base[1] * normFactor, base[2] * normFactor];
45077
+ }, [scale, normFactor]);
44322
45078
  const rotationRad = useMemo(() => {
44323
45079
  return [
44324
45080
  rotation[0] * Math.PI / 180,
@@ -44529,6 +45285,29 @@ var init_GameCanvas3D2 = __esm({
44529
45285
  const controlsRef = useRef(null);
44530
45286
  const [hoveredTile, setHoveredTile] = useState(null);
44531
45287
  const [internalError, setInternalError] = useState(null);
45288
+ useEffect(() => {
45289
+ const el = containerRef.current;
45290
+ if (!el) return;
45291
+ let node = el;
45292
+ let depth = 0;
45293
+ while (node && depth < 8) {
45294
+ const cs = window.getComputedStyle(node);
45295
+ const rect = node.getBoundingClientRect();
45296
+ console.log("[almadar:ui:game:3d-height]", {
45297
+ depth,
45298
+ tag: node.tagName,
45299
+ id: node.id || void 0,
45300
+ className: node.className?.slice?.(0, 60) || void 0,
45301
+ rectHeight: rect.height,
45302
+ computedHeight: cs.height,
45303
+ computedMinHeight: cs.minHeight,
45304
+ computedFlex: cs.flex,
45305
+ computedOverflow: cs.overflow
45306
+ });
45307
+ node = node.parentElement;
45308
+ depth++;
45309
+ }
45310
+ }, []);
44532
45311
  const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
44533
45312
  const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
44534
45313
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
@@ -44918,7 +45697,7 @@ var init_GameCanvas3D2 = __esm({
44918
45697
  {
44919
45698
  ref: containerRef,
44920
45699
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
44921
- style: { minHeight: "85vh" },
45700
+ style: { height: "85vh" },
44922
45701
  "data-orientation": orientation,
44923
45702
  "data-camera-mode": cameraMode,
44924
45703
  "data-overlay": overlay,
@@ -44933,7 +45712,7 @@ var init_GameCanvas3D2 = __esm({
44933
45712
  near: 0.1,
44934
45713
  far: 1e3
44935
45714
  },
44936
- style: { background: backgroundColor, height: "85vh", width: "100%" },
45715
+ style: { background: backgroundColor, position: "absolute", inset: 0 },
44937
45716
  onClick: (e) => {
44938
45717
  if (e.target === e.currentTarget) {
44939
45718
  eventHandlers.handleCanvasClick(e);
@@ -45904,7 +46683,7 @@ var init_List = __esm({
45904
46683
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
45905
46684
  return [];
45906
46685
  }, [entity]);
45907
- const getItemActions = React90__default.useCallback(
46686
+ const getItemActions = React93__default.useCallback(
45908
46687
  (item) => {
45909
46688
  if (!itemActions) return [];
45910
46689
  if (typeof itemActions === "function") {
@@ -46380,7 +47159,7 @@ var init_MediaGallery = __esm({
46380
47159
  [selectable, selectedItems, selectionEvent, eventBus]
46381
47160
  );
46382
47161
  const entityData = Array.isArray(entity) ? entity : [];
46383
- const items = React90__default.useMemo(() => {
47162
+ const items = React93__default.useMemo(() => {
46384
47163
  if (propItems) return propItems;
46385
47164
  if (entityData.length === 0) return [];
46386
47165
  return entityData.map((record, idx) => ({
@@ -46541,7 +47320,7 @@ var init_MediaGallery = __esm({
46541
47320
  }
46542
47321
  });
46543
47322
  function extractTitle2(children) {
46544
- if (!React90__default.isValidElement(children)) return void 0;
47323
+ if (!React93__default.isValidElement(children)) return void 0;
46545
47324
  const props = children.props;
46546
47325
  if (typeof props.title === "string") {
46547
47326
  return props.title;
@@ -47117,31 +47896,33 @@ var init_PricingPageTemplate = __esm({
47117
47896
  PricingPageTemplate.displayName = "PricingPageTemplate";
47118
47897
  }
47119
47898
  });
47120
- function dungeonTerrain(x, y, stairsX, stairsY) {
47899
+ function resolveManifestUrl3(manifest, relative) {
47900
+ if (relative == null) return void 0;
47901
+ if (/^https?:\/\//.test(relative)) return relative;
47902
+ const base = manifest?.baseUrl;
47903
+ if (base == null) return relative;
47904
+ const cleanBase = base.replace(/\/$/, "");
47905
+ const cleanRel = relative.replace(/^\//, "");
47906
+ return `${cleanBase}/${cleanRel}`;
47907
+ }
47908
+ function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
47121
47909
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
47122
47910
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
47123
47911
  const isWall = isBorder || isPillar;
47912
+ const terrains = manifest?.terrains;
47124
47913
  if (x === stairsX && y === stairsY) {
47125
- return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
47914
+ return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
47126
47915
  }
47127
47916
  if (isWall) {
47128
- return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
47129
- }
47130
- const variant = (x * 3 + y * 7) % 5;
47131
- const sprites = [
47132
- `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
47133
- `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
47134
- `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
47135
- `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
47136
- `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
47137
- ];
47138
- return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
47917
+ return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
47918
+ }
47919
+ return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
47139
47920
  }
47140
- function buildDefaultDungeonTiles(stairsX, stairsY) {
47921
+ function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
47141
47922
  const tiles = [];
47142
47923
  for (let y = 0; y < DUNGEON_GRID_H; y++) {
47143
47924
  for (let x = 0; x < DUNGEON_GRID_W; x++) {
47144
- tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
47925
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY, manifest) });
47145
47926
  }
47146
47927
  }
47147
47928
  return tiles;
@@ -47171,20 +47952,48 @@ function RoguelikeBoard({
47171
47952
  className
47172
47953
  }) {
47173
47954
  const board = boardEntity(entity) ?? {};
47174
- const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
47175
- const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
47176
- const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
47177
- const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
47178
- const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
47179
- const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
47955
+ const assetManifest = propAssetManifest ?? board.assetManifest;
47956
+ const stairsX = propStairsX ?? num(board.stairsX, 14);
47957
+ const stairsY = propStairsY ?? num(board.stairsY, 14);
47958
+ const entityTiles = useMemo(
47959
+ () => rows(board.tiles).map((r2) => ({
47960
+ x: num(r2.x),
47961
+ y: num(r2.y),
47962
+ terrain: r2.terrain == null ? void 0 : str(r2.terrain),
47963
+ terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
47964
+ passable: r2.passable !== false
47965
+ })),
47966
+ [board.tiles]
47967
+ );
47968
+ const tiles = propTiles ?? (entityTiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? entityTiles : buildDefaultDungeonTiles(stairsX, stairsY, assetManifest));
47969
+ const entityEnemies = useMemo(
47970
+ () => rows(board.enemies).map((r2) => ({
47971
+ id: str(r2.id),
47972
+ x: num(r2.x),
47973
+ y: num(r2.y),
47974
+ hp: num(r2.hp),
47975
+ attack: num(r2.attack)
47976
+ })),
47977
+ [board.enemies]
47978
+ );
47979
+ const enemies = propEnemies ?? (entityEnemies.length > 0 ? entityEnemies : DEFAULT_ENEMIES);
47980
+ const entityItems = useMemo(
47981
+ () => rows(board.items).map((r2) => ({
47982
+ id: str(r2.id),
47983
+ x: num(r2.x),
47984
+ y: num(r2.y),
47985
+ kind: str(r2.kind) || "health_potion"
47986
+ })),
47987
+ [board.items]
47988
+ );
47989
+ const items = propItems ?? (entityItems.length > 0 ? entityItems : DEFAULT_ITEMS);
47990
+ const player = propPlayer ?? (board.player == null ? { x: 1, y: 1 } : vec2(board.player));
47180
47991
  const playerHp = propPlayerHp ?? num(board.playerHp, 10);
47181
47992
  const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
47182
47993
  const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
47183
47994
  const depth = propDepth ?? num(board.depth, 1);
47184
47995
  const result = propResult ?? (str(board.result) || "none");
47185
47996
  const phase = propPhase ?? (str(board.phase) || "player_turn");
47186
- propStairsX ?? num(board.stairsX, 14);
47187
- propStairsY ?? num(board.stairsY, 14);
47188
47997
  const eventBus = useEventBus();
47189
47998
  const { t } = useTranslate();
47190
47999
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -47231,7 +48040,7 @@ function RoguelikeBoard({
47231
48040
  health: playerHp,
47232
48041
  maxHealth: playerMaxHp,
47233
48042
  unitType: "player",
47234
- sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
48043
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
47235
48044
  },
47236
48045
  ...liveEnemies.map((e) => ({
47237
48046
  id: e.id,
@@ -47241,19 +48050,19 @@ function RoguelikeBoard({
47241
48050
  health: e.hp,
47242
48051
  maxHealth: 6,
47243
48052
  unitType: "enemy",
47244
- sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
48053
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
47245
48054
  }))
47246
48055
  ];
47247
- }, [player, enemies, playerHp, playerMaxHp, t]);
48056
+ }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
47248
48057
  const isoFeatures = useMemo(
47249
48058
  () => items.map((it) => ({
47250
48059
  id: it.id,
47251
48060
  x: it.x,
47252
48061
  y: it.y,
47253
48062
  type: it.kind,
47254
- sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
48063
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
47255
48064
  })),
47256
- [items]
48065
+ [items, assetManifest]
47257
48066
  );
47258
48067
  const validMoves = useMemo(() => {
47259
48068
  if (result !== "none" || phase !== "player_turn") return [];
@@ -47312,8 +48121,8 @@ function RoguelikeBoard({
47312
48121
  onTileHover: (x, y) => setHoveredTile({ x, y }),
47313
48122
  onTileLeave: () => setHoveredTile(null),
47314
48123
  scale,
47315
- assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
47316
- assetManifest: propAssetManifest,
48124
+ assetBaseUrl: assetManifest?.baseUrl,
48125
+ assetManifest,
47317
48126
  unitScale,
47318
48127
  spriteHeightRatio,
47319
48128
  spriteMaxWidthRatio
@@ -47360,7 +48169,7 @@ function RoguelikeBoard({
47360
48169
  ] }) })
47361
48170
  ] });
47362
48171
  }
47363
- var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
48172
+ var DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS;
47364
48173
  var init_RoguelikeBoard = __esm({
47365
48174
  "components/game/organisms/RoguelikeBoard.tsx"() {
47366
48175
  "use client";
@@ -47372,10 +48181,8 @@ var init_RoguelikeBoard = __esm({
47372
48181
  init_Stack();
47373
48182
  init_IsometricCanvas();
47374
48183
  init_boardEntity();
47375
- CDN4 = "https://almadar-kflow-assets.web.app/shared";
47376
48184
  DUNGEON_GRID_W = 16;
47377
48185
  DUNGEON_GRID_H = 16;
47378
- buildDefaultDungeonTiles(14, 14);
47379
48186
  DEFAULT_ENEMIES = [
47380
48187
  { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
47381
48188
  { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
@@ -47387,11 +48194,6 @@ var init_RoguelikeBoard = __esm({
47387
48194
  { id: "i2", x: 7, y: 9, kind: "sword" },
47388
48195
  { id: "i3", x: 11, y: 5, kind: "shield" }
47389
48196
  ];
47390
- FEATURE_SPRITE = {
47391
- health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
47392
- sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
47393
- shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
47394
- };
47395
48197
  RoguelikeBoard.displayName = "RoguelikeBoard";
47396
48198
  }
47397
48199
  });
@@ -47429,40 +48231,40 @@ function RoguelikeTemplate({
47429
48231
  }
47430
48232
  );
47431
48233
  }
47432
- var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
48234
+ var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47433
48235
  var init_RoguelikeTemplate = __esm({
47434
48236
  "components/game/templates/RoguelikeTemplate.tsx"() {
47435
48237
  init_RoguelikeBoard();
47436
- CDN5 = "https://almadar-kflow-assets.web.app/shared";
48238
+ CDN4 = "https://almadar-kflow-assets.web.app/shared";
47437
48239
  DEFAULT_ROGUELIKE_TILES = [
47438
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47439
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47440
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47441
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47442
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47443
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47444
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47445
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47446
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47447
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47448
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47449
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47450
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47451
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47452
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47453
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47454
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47455
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47456
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
47457
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47458
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47459
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47460
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47461
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47462
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
48240
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48241
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48242
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48243
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48244
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48245
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48246
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48247
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48248
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48249
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48250
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48251
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48252
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48253
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48254
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48255
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48256
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48257
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48258
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
48259
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48260
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48261
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48262
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48263
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48264
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
47463
48265
  ];
47464
48266
  DEFAULT_ROGUELIKE_MANIFEST = {
47465
- baseUrl: CDN5,
48267
+ baseUrl: CDN4,
47466
48268
  terrains: {
47467
48269
  floor: "/isometric-dungeon/Isometric/dirt_E.png",
47468
48270
  wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
@@ -47588,7 +48390,7 @@ var init_debugRegistry = __esm({
47588
48390
  }
47589
48391
  });
47590
48392
  function useDebugData() {
47591
- const [data, setData] = React90.useState(() => ({
48393
+ const [data, setData] = React93.useState(() => ({
47592
48394
  traits: [],
47593
48395
  ticks: [],
47594
48396
  guards: [],
@@ -47602,7 +48404,7 @@ function useDebugData() {
47602
48404
  },
47603
48405
  lastUpdate: Date.now()
47604
48406
  }));
47605
- React90.useEffect(() => {
48407
+ React93.useEffect(() => {
47606
48408
  const updateData = () => {
47607
48409
  setData({
47608
48410
  traits: getAllTraits(),
@@ -47711,12 +48513,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
47711
48513
  return positions;
47712
48514
  }
47713
48515
  function WalkMinimap() {
47714
- const [walkStep, setWalkStep] = React90.useState(null);
47715
- const [traits2, setTraits] = React90.useState([]);
47716
- const [coveredEdges, setCoveredEdges] = React90.useState([]);
47717
- const [completedTraits, setCompletedTraits] = React90.useState(/* @__PURE__ */ new Set());
47718
- const prevTraitRef = React90.useRef(null);
47719
- React90.useEffect(() => {
48516
+ const [walkStep, setWalkStep] = React93.useState(null);
48517
+ const [traits2, setTraits] = React93.useState([]);
48518
+ const [coveredEdges, setCoveredEdges] = React93.useState([]);
48519
+ const [completedTraits, setCompletedTraits] = React93.useState(/* @__PURE__ */ new Set());
48520
+ const prevTraitRef = React93.useRef(null);
48521
+ React93.useEffect(() => {
47720
48522
  const interval = setInterval(() => {
47721
48523
  const w = window;
47722
48524
  const step = w.__orbitalWalkStep;
@@ -48152,15 +48954,15 @@ var init_EntitiesTab = __esm({
48152
48954
  });
48153
48955
  function EventFlowTab({ events: events2 }) {
48154
48956
  const { t } = useTranslate();
48155
- const [filter, setFilter] = React90.useState("all");
48156
- const containerRef = React90.useRef(null);
48157
- const [autoScroll, setAutoScroll] = React90.useState(true);
48158
- React90.useEffect(() => {
48957
+ const [filter, setFilter] = React93.useState("all");
48958
+ const containerRef = React93.useRef(null);
48959
+ const [autoScroll, setAutoScroll] = React93.useState(true);
48960
+ React93.useEffect(() => {
48159
48961
  if (autoScroll && containerRef.current) {
48160
48962
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
48161
48963
  }
48162
48964
  }, [events2.length, autoScroll]);
48163
- const filteredEvents = React90.useMemo(() => {
48965
+ const filteredEvents = React93.useMemo(() => {
48164
48966
  if (filter === "all") return events2;
48165
48967
  return events2.filter((e) => e.type === filter);
48166
48968
  }, [events2, filter]);
@@ -48276,7 +49078,7 @@ var init_EventFlowTab = __esm({
48276
49078
  });
48277
49079
  function GuardsPanel({ guards }) {
48278
49080
  const { t } = useTranslate();
48279
- const [filter, setFilter] = React90.useState("all");
49081
+ const [filter, setFilter] = React93.useState("all");
48280
49082
  if (guards.length === 0) {
48281
49083
  return /* @__PURE__ */ jsx(
48282
49084
  EmptyState,
@@ -48289,7 +49091,7 @@ function GuardsPanel({ guards }) {
48289
49091
  }
48290
49092
  const passedCount = guards.filter((g) => g.result).length;
48291
49093
  const failedCount = guards.length - passedCount;
48292
- const filteredGuards = React90.useMemo(() => {
49094
+ const filteredGuards = React93.useMemo(() => {
48293
49095
  if (filter === "all") return guards;
48294
49096
  if (filter === "passed") return guards.filter((g) => g.result);
48295
49097
  return guards.filter((g) => !g.result);
@@ -48452,10 +49254,10 @@ function EffectBadge({ effect }) {
48452
49254
  }
48453
49255
  function TransitionTimeline({ transitions }) {
48454
49256
  const { t } = useTranslate();
48455
- const containerRef = React90.useRef(null);
48456
- const [autoScroll, setAutoScroll] = React90.useState(true);
48457
- const [expandedId, setExpandedId] = React90.useState(null);
48458
- React90.useEffect(() => {
49257
+ const containerRef = React93.useRef(null);
49258
+ const [autoScroll, setAutoScroll] = React93.useState(true);
49259
+ const [expandedId, setExpandedId] = React93.useState(null);
49260
+ React93.useEffect(() => {
48459
49261
  if (autoScroll && containerRef.current) {
48460
49262
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
48461
49263
  }
@@ -48735,9 +49537,9 @@ function getAllEvents(traits2) {
48735
49537
  function EventDispatcherTab({ traits: traits2, schema }) {
48736
49538
  const eventBus = useEventBus();
48737
49539
  const { t } = useTranslate();
48738
- const [log15, setLog] = React90.useState([]);
48739
- const prevStatesRef = React90.useRef(/* @__PURE__ */ new Map());
48740
- React90.useEffect(() => {
49540
+ const [log15, setLog] = React93.useState([]);
49541
+ const prevStatesRef = React93.useRef(/* @__PURE__ */ new Map());
49542
+ React93.useEffect(() => {
48741
49543
  for (const trait of traits2) {
48742
49544
  const prev = prevStatesRef.current.get(trait.id);
48743
49545
  if (prev && prev !== trait.currentState) {
@@ -48906,10 +49708,10 @@ function VerifyModePanel({
48906
49708
  localCount
48907
49709
  }) {
48908
49710
  const { t } = useTranslate();
48909
- const [expanded, setExpanded] = React90.useState(true);
48910
- const scrollRef = React90.useRef(null);
48911
- const prevCountRef = React90.useRef(0);
48912
- React90.useEffect(() => {
49711
+ const [expanded, setExpanded] = React93.useState(true);
49712
+ const scrollRef = React93.useRef(null);
49713
+ const prevCountRef = React93.useRef(0);
49714
+ React93.useEffect(() => {
48913
49715
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
48914
49716
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
48915
49717
  }
@@ -48966,10 +49768,10 @@ function RuntimeDebugger({
48966
49768
  schema
48967
49769
  }) {
48968
49770
  const { t } = useTranslate();
48969
- const [isCollapsed, setIsCollapsed] = React90.useState(mode === "verify" ? true : defaultCollapsed);
48970
- const [isVisible, setIsVisible] = React90.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
49771
+ const [isCollapsed, setIsCollapsed] = React93.useState(mode === "verify" ? true : defaultCollapsed);
49772
+ const [isVisible, setIsVisible] = React93.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
48971
49773
  const debugData = useDebugData();
48972
- React90.useEffect(() => {
49774
+ React93.useEffect(() => {
48973
49775
  if (mode === "inline") return;
48974
49776
  return onDebugToggle((enabled) => {
48975
49777
  setIsVisible(enabled);
@@ -48978,7 +49780,7 @@ function RuntimeDebugger({
48978
49780
  }
48979
49781
  });
48980
49782
  }, [mode]);
48981
- React90.useEffect(() => {
49783
+ React93.useEffect(() => {
48982
49784
  if (mode === "inline") return;
48983
49785
  const handleKeyDown = (e) => {
48984
49786
  if (e.key === "`" && isVisible) {
@@ -49538,7 +50340,7 @@ function SequenceBar({
49538
50340
  onSlotRemove(index);
49539
50341
  }, [onSlotRemove, playing]);
49540
50342
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
49541
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
50343
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
49542
50344
  i > 0 && /* @__PURE__ */ jsx(
49543
50345
  Typography,
49544
50346
  {
@@ -50427,7 +51229,7 @@ var init_StatCard = __esm({
50427
51229
  const labelToUse = propLabel ?? propTitle;
50428
51230
  const eventBus = useEventBus();
50429
51231
  const { t } = useTranslate();
50430
- const handleActionClick = React90__default.useCallback(() => {
51232
+ const handleActionClick = React93__default.useCallback(() => {
50431
51233
  if (action?.event) {
50432
51234
  eventBus.emit(`UI:${action.event}`, {});
50433
51235
  }
@@ -50438,7 +51240,7 @@ var init_StatCard = __esm({
50438
51240
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
50439
51241
  const isLoading = externalLoading ?? false;
50440
51242
  const error = externalError;
50441
- const computeMetricValue = React90__default.useCallback(
51243
+ const computeMetricValue = React93__default.useCallback(
50442
51244
  (metric, items) => {
50443
51245
  if (metric.value !== void 0) {
50444
51246
  return metric.value;
@@ -50477,7 +51279,7 @@ var init_StatCard = __esm({
50477
51279
  },
50478
51280
  []
50479
51281
  );
50480
- const schemaStats = React90__default.useMemo(() => {
51282
+ const schemaStats = React93__default.useMemo(() => {
50481
51283
  if (!metrics || metrics.length === 0) return null;
50482
51284
  return metrics.map((metric) => ({
50483
51285
  label: metric.label,
@@ -50485,7 +51287,7 @@ var init_StatCard = __esm({
50485
51287
  format: metric.format
50486
51288
  }));
50487
51289
  }, [metrics, data, computeMetricValue]);
50488
- const calculatedTrend = React90__default.useMemo(() => {
51290
+ const calculatedTrend = React93__default.useMemo(() => {
50489
51291
  if (manualTrend !== void 0) return manualTrend;
50490
51292
  if (previousValue === void 0 || currentValue === void 0)
50491
51293
  return void 0;
@@ -51451,7 +52253,7 @@ var init_Timeline = __esm({
51451
52253
  }) => {
51452
52254
  const { t } = useTranslate();
51453
52255
  const entityData = Array.isArray(entity) ? entity : [];
51454
- const items = React90__default.useMemo(() => {
52256
+ const items = React93__default.useMemo(() => {
51455
52257
  if (propItems) return propItems;
51456
52258
  if (entityData.length === 0) return [];
51457
52259
  return entityData.map((record, idx) => {
@@ -51558,7 +52360,7 @@ var init_Timeline = __esm({
51558
52360
  }
51559
52361
  });
51560
52362
  function extractToastProps(children) {
51561
- if (!React90__default.isValidElement(children)) {
52363
+ if (!React93__default.isValidElement(children)) {
51562
52364
  if (typeof children === "string") {
51563
52365
  return { message: children };
51564
52366
  }
@@ -51596,7 +52398,7 @@ var init_ToastSlot = __esm({
51596
52398
  eventBus.emit("UI:CLOSE");
51597
52399
  };
51598
52400
  if (!isVisible) return null;
51599
- const isCustomContent = React90__default.isValidElement(children) && !message;
52401
+ const isCustomContent = React93__default.isValidElement(children) && !message;
51600
52402
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
51601
52403
  Toast,
51602
52404
  {
@@ -51612,82 +52414,442 @@ var init_ToastSlot = __esm({
51612
52414
  ToastSlot.displayName = "ToastSlot";
51613
52415
  }
51614
52416
  });
52417
+ function resolveManifestUrl4(manifest, relative) {
52418
+ if (relative == null || relative === "") return void 0;
52419
+ if (/^https?:\/\//.test(relative)) return relative;
52420
+ const base = manifest?.baseUrl;
52421
+ if (base == null) return relative;
52422
+ const cleanBase = base.replace(/\/$/, "");
52423
+ const cleanRel = relative.replace(/^\//, "");
52424
+ return `${cleanBase}/${cleanRel}`;
52425
+ }
52426
+ function readPlayer(v) {
52427
+ if (v == null || typeof v !== "object") return void 0;
52428
+ const o = v;
52429
+ return { x: num(o.x), y: num(o.y) };
52430
+ }
52431
+ function TopDownShooterBoard({
52432
+ entity,
52433
+ player: propPlayer,
52434
+ enemies: propEnemies,
52435
+ projectiles: propProjectiles,
52436
+ score: propScore,
52437
+ wave: propWave,
52438
+ lives: propLives,
52439
+ result: propResult,
52440
+ assetManifest: propAssetManifest,
52441
+ width = DEFAULT_WIDTH,
52442
+ height = DEFAULT_HEIGHT,
52443
+ spriteSize = 32,
52444
+ moveEvent = "MOVE",
52445
+ fireEvent = "FIRE",
52446
+ playAgainEvent = "PLAY_AGAIN",
52447
+ gameEndEvent = "GAME_END",
52448
+ className
52449
+ }) {
52450
+ const board = boardEntity(entity) ?? {};
52451
+ const eventBus = useEventBus();
52452
+ const { t } = useTranslate();
52453
+ const assetManifest = propAssetManifest ?? board.assetManifest;
52454
+ const player = propPlayer ?? readPlayer(board.player) ?? { x: width / 2, y: height - spriteSize };
52455
+ const enemies = useMemo(
52456
+ () => propEnemies ?? rows(board.enemies).map((r2) => ({
52457
+ id: str(r2.id),
52458
+ x: num(r2.x),
52459
+ y: num(r2.y),
52460
+ hp: num(r2.hp, 1)
52461
+ })),
52462
+ [propEnemies, board.enemies]
52463
+ );
52464
+ const projectiles = useMemo(
52465
+ () => propProjectiles ?? rows(board.projectiles).map((r2) => ({
52466
+ id: str(r2.id),
52467
+ x: num(r2.x),
52468
+ y: num(r2.y),
52469
+ vx: num(r2.vx),
52470
+ vy: num(r2.vy)
52471
+ })),
52472
+ [propProjectiles, board.projectiles]
52473
+ );
52474
+ const score = propScore ?? num(board.score, 0);
52475
+ const wave = propWave ?? num(board.wave, 1);
52476
+ const lives = propLives ?? num(board.lives, 3);
52477
+ const result = propResult ?? (str(board.result) || "none");
52478
+ const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
52479
+ const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
52480
+ const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
52481
+ const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
52482
+ const spriteUrls = useMemo(
52483
+ () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
52484
+ [playerSprite, enemySprite, projectileSprite]
52485
+ );
52486
+ const { getImage } = useImageCache(spriteUrls);
52487
+ const sceneRef = useRef({ player, enemies, projectiles, playerSprite, enemySprite, projectileSprite });
52488
+ sceneRef.current = { player, enemies, projectiles, playerSprite, enemySprite, projectileSprite };
52489
+ boardLog2.debug("shooter-resolve", {
52490
+ player: { x: player.x, y: player.y },
52491
+ enemyCount: enemies.length,
52492
+ projectileCount: projectiles.length,
52493
+ wave,
52494
+ lives,
52495
+ result,
52496
+ hasPlayerSprite: playerSprite != null
52497
+ });
52498
+ const onDraw = useCallback(
52499
+ (ctx, _frame) => {
52500
+ const scene = sceneRef.current;
52501
+ ctx.fillStyle = "#10141c";
52502
+ ctx.fillRect(0, 0, width, height);
52503
+ const half = spriteSize / 2;
52504
+ for (const p2 of scene.projectiles) {
52505
+ const img = scene.projectileSprite ? getImage(scene.projectileSprite) : void 0;
52506
+ if (img) {
52507
+ ctx.drawImage(img, p2.x - half / 2, p2.y - half / 2, spriteSize / 2, spriteSize / 2);
52508
+ } else {
52509
+ ctx.fillStyle = "#ffd34d";
52510
+ ctx.beginPath();
52511
+ ctx.arc(p2.x, p2.y, spriteSize / 6, 0, Math.PI * 2);
52512
+ ctx.fill();
52513
+ }
52514
+ }
52515
+ for (const e of scene.enemies) {
52516
+ const img = scene.enemySprite ? getImage(scene.enemySprite) : void 0;
52517
+ if (img) {
52518
+ ctx.drawImage(img, e.x - half, e.y - half, spriteSize, spriteSize);
52519
+ } else {
52520
+ ctx.fillStyle = "#e0524d";
52521
+ ctx.fillRect(e.x - half, e.y - half, spriteSize, spriteSize);
52522
+ }
52523
+ }
52524
+ const pImg = scene.playerSprite ? getImage(scene.playerSprite) : void 0;
52525
+ if (pImg) {
52526
+ ctx.drawImage(pImg, scene.player.x - half, scene.player.y - half, spriteSize, spriteSize);
52527
+ } else {
52528
+ ctx.fillStyle = "#4da3ff";
52529
+ ctx.beginPath();
52530
+ ctx.moveTo(scene.player.x, scene.player.y - half);
52531
+ ctx.lineTo(scene.player.x + half, scene.player.y + half);
52532
+ ctx.lineTo(scene.player.x - half, scene.player.y + half);
52533
+ ctx.closePath();
52534
+ ctx.fill();
52535
+ }
52536
+ },
52537
+ [getImage, width, height, spriteSize]
52538
+ );
52539
+ const moveEventRef = useRef(moveEvent);
52540
+ moveEventRef.current = moveEvent;
52541
+ const fireEventRef = useRef(fireEvent);
52542
+ fireEventRef.current = fireEvent;
52543
+ const resultRef = useRef(result);
52544
+ resultRef.current = result;
52545
+ const playerRef = useRef(player);
52546
+ playerRef.current = player;
52547
+ useEffect(() => {
52548
+ function onKeyDown(e) {
52549
+ if (resultRef.current !== "none") return;
52550
+ let dx = 0;
52551
+ let dy = 0;
52552
+ switch (e.key) {
52553
+ case "ArrowUp":
52554
+ case "w":
52555
+ dy = -1;
52556
+ break;
52557
+ case "ArrowDown":
52558
+ case "s":
52559
+ dy = 1;
52560
+ break;
52561
+ case "ArrowLeft":
52562
+ case "a":
52563
+ dx = -1;
52564
+ break;
52565
+ case "ArrowRight":
52566
+ case "d":
52567
+ dx = 1;
52568
+ break;
52569
+ case " ": {
52570
+ e.preventDefault();
52571
+ const evt = fireEventRef.current;
52572
+ if (evt) {
52573
+ eventBus.emit(`UI:${evt}`, { tx: playerRef.current.x, ty: 0 });
52574
+ }
52575
+ return;
52576
+ }
52577
+ default:
52578
+ return;
52579
+ }
52580
+ e.preventDefault();
52581
+ const moveEvt = moveEventRef.current;
52582
+ if (moveEvt) {
52583
+ eventBus.emit(`UI:${moveEvt}`, { dx, dy });
52584
+ }
52585
+ }
52586
+ window.addEventListener("keydown", onKeyDown);
52587
+ return () => window.removeEventListener("keydown", onKeyDown);
52588
+ }, [eventBus]);
52589
+ const handleFireClick = useCallback(
52590
+ (e) => {
52591
+ if (result !== "none") return;
52592
+ const evt = fireEventRef.current;
52593
+ if (!evt) return;
52594
+ const rect = e.currentTarget.getBoundingClientRect();
52595
+ const tx = e.clientX - rect.left;
52596
+ const ty = e.clientY - rect.top;
52597
+ eventBus.emit(`UI:${evt}`, { tx, ty });
52598
+ },
52599
+ [result, eventBus]
52600
+ );
52601
+ const handlePlayAgain = useCallback(() => {
52602
+ if (playAgainEvent) {
52603
+ eventBus.emit(`UI:${playAgainEvent}`, {});
52604
+ }
52605
+ }, [playAgainEvent, eventBus]);
52606
+ const gameEndEmittedRef = useRef(false);
52607
+ useEffect(() => {
52608
+ if ((result === "won" || result === "lost") && gameEndEvent) {
52609
+ if (!gameEndEmittedRef.current) {
52610
+ gameEndEmittedRef.current = true;
52611
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
52612
+ }
52613
+ } else {
52614
+ gameEndEmittedRef.current = false;
52615
+ }
52616
+ }, [result, gameEndEvent, eventBus]);
52617
+ const isGameOver = result === "won" || result === "lost";
52618
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("top-down-shooter-board relative bg-background", className), gap: "none", children: [
52619
+ /* @__PURE__ */ jsxs(HStack, { className: "px-4 py-2 border-b border-border bg-surface", gap: "lg", align: "center", children: [
52620
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
52621
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.score") ?? "Score" }),
52622
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: score })
52623
+ ] }),
52624
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
52625
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.wave") ?? "Wave" }),
52626
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: wave })
52627
+ ] }),
52628
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
52629
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.lives") ?? "Lives" }),
52630
+ /* @__PURE__ */ jsx(
52631
+ Typography,
52632
+ {
52633
+ variant: "body2",
52634
+ weight: "bold",
52635
+ className: lives <= 1 ? "text-error" : "text-success",
52636
+ children: lives
52637
+ }
52638
+ )
52639
+ ] })
52640
+ ] }),
52641
+ /* @__PURE__ */ jsxs(Box, { className: "relative", onClick: handleFireClick, children: [
52642
+ /* @__PURE__ */ jsx(
52643
+ GameCanvas2D,
52644
+ {
52645
+ width,
52646
+ height,
52647
+ backgroundImage: backgroundSprite,
52648
+ assetBaseUrl: assetManifest?.baseUrl,
52649
+ onDraw
52650
+ }
52651
+ ),
52652
+ 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: [
52653
+ /* @__PURE__ */ jsx(
52654
+ Typography,
52655
+ {
52656
+ variant: "h2",
52657
+ className: cn(
52658
+ "text-4xl font-black tracking-widest uppercase",
52659
+ result === "won" ? "text-warning" : "text-error"
52660
+ ),
52661
+ children: result === "won" ? t("shooter.victory") ?? "Victory!" : t("shooter.defeat") ?? "Defeat!"
52662
+ }
52663
+ ),
52664
+ /* @__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." }),
52665
+ /* @__PURE__ */ jsx(
52666
+ Button,
52667
+ {
52668
+ variant: "primary",
52669
+ className: "px-8 py-3 font-semibold",
52670
+ onClick: handlePlayAgain,
52671
+ children: t("shooter.playAgain") ?? "Play Again"
52672
+ }
52673
+ )
52674
+ ] }) })
52675
+ ] })
52676
+ ] });
52677
+ }
52678
+ var boardLog2, DEFAULT_WIDTH, DEFAULT_HEIGHT;
52679
+ var init_TopDownShooterBoard = __esm({
52680
+ "components/game/organisms/TopDownShooterBoard.tsx"() {
52681
+ "use client";
52682
+ init_cn();
52683
+ init_useEventBus();
52684
+ init_Box();
52685
+ init_Button();
52686
+ init_Typography();
52687
+ init_Stack();
52688
+ init_GameCanvas2D();
52689
+ init_useImageCache();
52690
+ init_boardEntity();
52691
+ boardLog2 = createLogger("almadar:ui:game:top-down-shooter-board");
52692
+ DEFAULT_WIDTH = 640;
52693
+ DEFAULT_HEIGHT = 480;
52694
+ TopDownShooterBoard.displayName = "TopDownShooterBoard";
52695
+ }
52696
+ });
52697
+ function isEntityRow3(value) {
52698
+ return value != null && typeof value === "object" && !Array.isArray(value);
52699
+ }
52700
+ function TopDownShooterTemplate({
52701
+ entity,
52702
+ title = "Arena Shooter",
52703
+ player,
52704
+ enemies,
52705
+ projectiles,
52706
+ score,
52707
+ wave,
52708
+ lives,
52709
+ result,
52710
+ assetManifest,
52711
+ width,
52712
+ height,
52713
+ spriteSize,
52714
+ moveEvent,
52715
+ fireEvent,
52716
+ playAgainEvent,
52717
+ gameEndEvent,
52718
+ className
52719
+ }) {
52720
+ const resolved = isEntityRow3(entity) ? entity : void 0;
52721
+ return /* @__PURE__ */ jsxs(
52722
+ Box,
52723
+ {
52724
+ display: "flex",
52725
+ fullHeight: true,
52726
+ className: cn("top-down-shooter-template flex-col", className),
52727
+ children: [
52728
+ /* @__PURE__ */ jsx(
52729
+ HStack,
52730
+ {
52731
+ gap: "sm",
52732
+ align: "center",
52733
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
52734
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
52735
+ }
52736
+ ),
52737
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
52738
+ TopDownShooterBoard,
52739
+ {
52740
+ entity: resolved,
52741
+ player,
52742
+ enemies,
52743
+ projectiles,
52744
+ score,
52745
+ wave,
52746
+ lives,
52747
+ result,
52748
+ assetManifest,
52749
+ width,
52750
+ height,
52751
+ spriteSize,
52752
+ moveEvent,
52753
+ fireEvent,
52754
+ playAgainEvent,
52755
+ gameEndEvent,
52756
+ className: "h-full"
52757
+ }
52758
+ ) })
52759
+ ]
52760
+ }
52761
+ );
52762
+ }
52763
+ var init_TopDownShooterTemplate = __esm({
52764
+ "components/game/templates/TopDownShooterTemplate.tsx"() {
52765
+ init_cn();
52766
+ init_Box();
52767
+ init_Stack();
52768
+ init_Typography();
52769
+ init_TopDownShooterBoard();
52770
+ TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
52771
+ }
52772
+ });
52773
+ function resolveManifestUrl5(manifest, relative) {
52774
+ if (relative == null) return void 0;
52775
+ if (/^https?:\/\//.test(relative)) return relative;
52776
+ const base = manifest?.baseUrl;
52777
+ if (base == null) return relative;
52778
+ const cleanBase = base.replace(/\/$/, "");
52779
+ const cleanRel = relative.replace(/^\//, "");
52780
+ return `${cleanBase}/${cleanRel}`;
52781
+ }
51615
52782
  function buildDefaultTDTiles() {
51616
52783
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
51617
52784
  const tiles = [];
51618
52785
  for (let y = 0; y < TD_GRID_H; y++) {
51619
52786
  for (let x = 0; x < TD_GRID_W; x++) {
51620
52787
  if (pathSet.has(`${x},${y}`)) {
51621
- tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
52788
+ tiles.push({ x, y, terrain: "path", passable: false });
51622
52789
  } else {
51623
52790
  const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
51624
- const terrainKey = ["ground", "grass", "dirt"][variant];
51625
- tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
52791
+ const terrainKey = ["ground", "grass", "stone"][variant];
52792
+ tiles.push({ x, y, terrain: terrainKey, passable: true });
51626
52793
  }
51627
52794
  }
51628
52795
  }
51629
52796
  return tiles;
51630
52797
  }
51631
- function tilesToIso(tiles) {
51632
- return tiles.map((t) => ({
51633
- x: t.x,
51634
- y: t.y,
51635
- terrain: t.terrain,
51636
- terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
51637
- passable: t.passable
51638
- }));
51639
- }
51640
- function towersToUnits(towers) {
51641
- return towers.map((t) => ({
51642
- id: t.id,
51643
- position: { x: t.x, y: t.y },
51644
- name: "Tower",
51645
- team: "player",
51646
- sprite: TOWER_SPRITE,
51647
- unitType: "guardian",
51648
- health: 1,
51649
- maxHealth: 1
51650
- }));
52798
+ function tilesToIso2(tiles, manifest) {
52799
+ return tiles.map((t) => {
52800
+ const key = t.terrain ?? "ground";
52801
+ const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
52802
+ return {
52803
+ x: t.x,
52804
+ y: t.y,
52805
+ terrain: t.terrain,
52806
+ terrainSprite: sprite,
52807
+ passable: t.passable
52808
+ };
52809
+ });
51651
52810
  }
51652
- function creepsToUnits(creeps) {
52811
+ function creepsToUnits(creeps, manifest) {
52812
+ const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
51653
52813
  return creeps.map((c) => ({
51654
52814
  id: c.id,
51655
52815
  position: { x: c.x, y: c.y },
51656
52816
  name: "Creep",
51657
52817
  team: "enemy",
51658
- sprite: CREEP_SPRITE,
51659
- unitType: "scrapper",
52818
+ sprite,
52819
+ unitType: "creep",
51660
52820
  health: c.hp,
51661
52821
  maxHealth: c.maxHp
51662
52822
  }));
51663
52823
  }
51664
- function pathToFeatures(path) {
51665
- return path.map((p2, i) => ({
51666
- id: `path-${i}`,
51667
- x: p2.x,
51668
- y: p2.y,
51669
- type: "path-marker",
51670
- sprite: `${CDN6}world-map/road_straight.png`
51671
- }));
51672
- }
51673
- function heroToUnit(hero) {
52824
+ function heroToUnit(hero, manifest) {
51674
52825
  return {
51675
52826
  id: hero.id,
51676
52827
  position: { x: hero.x, y: hero.y },
51677
52828
  name: "Hero",
51678
52829
  team: "player",
51679
- sprite: HERO_SPRITE,
51680
- unitType: "amir",
52830
+ sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
52831
+ unitType: "hero",
51681
52832
  health: 1,
51682
52833
  maxHealth: 1
51683
52834
  };
51684
52835
  }
52836
+ function towersToFeatures(towers, manifest) {
52837
+ const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
52838
+ return towers.map((t) => ({
52839
+ id: t.id,
52840
+ x: t.x,
52841
+ y: t.y,
52842
+ type: "tower",
52843
+ sprite
52844
+ }));
52845
+ }
51685
52846
  function TowerDefenseBoard({
51686
52847
  entity,
51687
52848
  tiles: propTiles,
51688
52849
  path: propPath,
51689
52850
  towers: propTowers,
51690
52851
  creeps: propCreeps,
52852
+ assetManifest: propAssetManifest,
51691
52853
  hero: propHero,
51692
52854
  gold: propGold,
51693
52855
  lives: propLives,
@@ -51710,12 +52872,51 @@ function TowerDefenseBoard({
51710
52872
  const board = boardEntity(entity) ?? {};
51711
52873
  const eventBus = useEventBus();
51712
52874
  const { t } = useTranslate();
51713
- const rawTiles = propTiles ?? rows(board.tiles);
52875
+ const assetManifest = propAssetManifest ?? board.assetManifest;
52876
+ const entityTiles = useMemo(
52877
+ () => rows(board.tiles).map((r2) => ({
52878
+ x: num(r2.x),
52879
+ y: num(r2.y),
52880
+ terrain: r2.terrain == null ? void 0 : str(r2.terrain),
52881
+ terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
52882
+ passable: r2.passable !== false
52883
+ })),
52884
+ [board.tiles]
52885
+ );
52886
+ const rawTiles = propTiles ?? entityTiles;
51714
52887
  const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
51715
- const rawPath = propPath ?? rows(board.path);
52888
+ const entityPath = useMemo(
52889
+ () => rows(board.path).map((r2) => ({ x: num(r2.x), y: num(r2.y) })),
52890
+ [board.path]
52891
+ );
52892
+ const rawPath = propPath ?? entityPath;
51716
52893
  const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
51717
- const towers = propTowers ?? rows(board.towers);
51718
- const creeps = propCreeps ?? rows(board.creeps);
52894
+ const entityTowers = useMemo(
52895
+ () => rows(board.towers).map((r2) => ({
52896
+ id: str(r2.id),
52897
+ x: num(r2.x),
52898
+ y: num(r2.y),
52899
+ range: num(r2.range),
52900
+ damage: num(r2.damage),
52901
+ cooldown: num(r2.cooldown),
52902
+ lastFiredAt: r2.lastFiredAt == null ? void 0 : num(r2.lastFiredAt)
52903
+ })),
52904
+ [board.towers]
52905
+ );
52906
+ const towers = propTowers ?? entityTowers;
52907
+ const entityCreeps = useMemo(
52908
+ () => rows(board.creeps).map((r2) => ({
52909
+ id: str(r2.id),
52910
+ x: num(r2.x),
52911
+ y: num(r2.y),
52912
+ hp: num(r2.hp),
52913
+ maxHp: num(r2.maxHp),
52914
+ pathIndex: num(r2.pathIndex),
52915
+ speed: num(r2.speed)
52916
+ })),
52917
+ [board.creeps]
52918
+ );
52919
+ const creeps = propCreeps ?? entityCreeps;
51719
52920
  const hero = propHero ?? { id: "hero", x: 8, y: 8 };
51720
52921
  const gold = propGold ?? num(board.gold, 100);
51721
52922
  const lives = propLives ?? num(board.lives, 20);
@@ -51767,12 +52968,11 @@ function TowerDefenseBoard({
51767
52968
  (t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
51768
52969
  ).map((t2) => ({ x: t2.x, y: t2.y }));
51769
52970
  }, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
51770
- const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
51771
- const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
51772
- const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
51773
- const heroUnit = useMemo(() => heroToUnit(hero), [hero]);
51774
- const isoUnits = useMemo(() => [...towerUnits, ...creepUnits, heroUnit], [towerUnits, creepUnits, heroUnit]);
51775
- const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
52971
+ const isoTiles = useMemo(() => tilesToIso2(tiles, assetManifest), [tiles, assetManifest]);
52972
+ const creepUnits = useMemo(() => creepsToUnits(creeps, assetManifest), [creeps, assetManifest]);
52973
+ const heroUnit = useMemo(() => heroToUnit(hero, assetManifest), [hero, assetManifest]);
52974
+ const isoUnits = useMemo(() => [...creepUnits, heroUnit], [creepUnits, heroUnit]);
52975
+ const towerFeatures = useMemo(() => towersToFeatures(towers, assetManifest), [towers, assetManifest]);
51776
52976
  const handleTileClick = useCallback((x, y) => {
51777
52977
  if (result !== "none") return;
51778
52978
  if (pathPositions.has(`${x},${y}`)) return;
@@ -51831,7 +53031,9 @@ function TowerDefenseBoard({
51831
53031
  {
51832
53032
  tiles: isoTiles,
51833
53033
  units: isoUnits,
51834
- features: pathFeatures,
53034
+ features: towerFeatures,
53035
+ assetBaseUrl: assetManifest?.baseUrl,
53036
+ assetManifest,
51835
53037
  validMoves,
51836
53038
  hoveredTile,
51837
53039
  onTileClick: handleTileClick,
@@ -51870,7 +53072,7 @@ function TowerDefenseBoard({
51870
53072
  ] }) })
51871
53073
  ] });
51872
53074
  }
51873
- var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE, HERO_SPRITE;
53075
+ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
51874
53076
  var init_TowerDefenseBoard = __esm({
51875
53077
  "components/game/organisms/TowerDefenseBoard.tsx"() {
51876
53078
  "use client";
@@ -51882,16 +53084,8 @@ var init_TowerDefenseBoard = __esm({
51882
53084
  init_Stack();
51883
53085
  init_IsometricCanvas();
51884
53086
  init_boardEntity();
51885
- CDN6 = "https://almadar-kflow-assets.web.app/shared/";
51886
53087
  TD_GRID_W = 16;
51887
53088
  TD_GRID_H = 16;
51888
- TERRAIN_SPRITES = {
51889
- ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
51890
- path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
51891
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
51892
- grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
51893
- dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
51894
- };
51895
53089
  DEFAULT_TD_PATH = [
51896
53090
  { x: 2, y: 0 },
51897
53091
  { x: 2, y: 1 },
@@ -51944,9 +53138,6 @@ var init_TowerDefenseBoard = __esm({
51944
53138
  { x: 13, y: 15 }
51945
53139
  ];
51946
53140
  DEFAULT_TD_TILES = buildDefaultTDTiles();
51947
- TOWER_SPRITE = `${CDN6}sprite-sheets/guardian-sprite-sheet-se.png`;
51948
- CREEP_SPRITE = `${CDN6}sprite-sheets/scrapper-sprite-sheet-se.png`;
51949
- HERO_SPRITE = `${CDN6}sprite-sheets/amir-sprite-sheet-se.png`;
51950
53141
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
51951
53142
  }
51952
53143
  });
@@ -52214,6 +53405,214 @@ var init_UncontrolledBattleBoard = __esm({
52214
53405
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
52215
53406
  }
52216
53407
  });
53408
+ function resolveManifestUrl6(manifest, relative) {
53409
+ if (relative == null) return void 0;
53410
+ if (/^https?:\/\//.test(relative)) return relative;
53411
+ const base = manifest?.baseUrl;
53412
+ if (base == null) return relative;
53413
+ const cleanBase = base.replace(/\/$/, "");
53414
+ const cleanRel = relative.replace(/^\//, "");
53415
+ return `${cleanBase}/${cleanRel}`;
53416
+ }
53417
+ function VisualNovelBoard({
53418
+ entity,
53419
+ nodes: propNodes,
53420
+ currentNodeId: propCurrentNodeId,
53421
+ assetManifest: propAssetManifest,
53422
+ typewriterSpeed = 30,
53423
+ portraitScale = 1,
53424
+ chooseEvent,
53425
+ advanceEvent,
53426
+ restartEvent,
53427
+ className
53428
+ }) {
53429
+ const board = boardEntity(entity) ?? {};
53430
+ const eventBus = useEventBus();
53431
+ const assetManifest = propAssetManifest ?? board.assetManifest;
53432
+ const entityNodes = useMemo(
53433
+ () => rows(board.nodes).map((r2) => ({
53434
+ id: str(r2.id),
53435
+ speaker: str(r2.speaker),
53436
+ text: str(r2.text),
53437
+ backgroundKey: r2.backgroundKey == null ? void 0 : str(r2.backgroundKey),
53438
+ portraitKey: r2.portraitKey == null ? void 0 : str(r2.portraitKey),
53439
+ choices: rows(r2.choices).map((c) => ({
53440
+ label: str(c.label),
53441
+ nextId: str(c.nextId)
53442
+ }))
53443
+ })),
53444
+ [board.nodes]
53445
+ );
53446
+ const rawNodes = propNodes ?? entityNodes;
53447
+ const nodes = rawNodes.length > 0 ? rawNodes : DEFAULT_NODES;
53448
+ const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
53449
+ const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
53450
+ const backgroundImage = useMemo(
53451
+ () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
53452
+ [assetManifest, currentNode?.backgroundKey]
53453
+ );
53454
+ const portraitUrl = useMemo(
53455
+ () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
53456
+ [assetManifest, currentNode?.portraitKey]
53457
+ );
53458
+ const dialogueChoices = useMemo(
53459
+ () => (currentNode?.choices ?? []).map((c) => ({ text: c.label, next: c.nextId })),
53460
+ [currentNode?.choices]
53461
+ );
53462
+ const handleChoice = useCallback(
53463
+ (choice) => {
53464
+ const index = dialogueChoices.findIndex((c) => c.next === choice.next && c.text === choice.text);
53465
+ if (chooseEvent) {
53466
+ eventBus.emit(`UI:${chooseEvent}`, { choiceIndex: index });
53467
+ }
53468
+ },
53469
+ [dialogueChoices, chooseEvent, eventBus]
53470
+ );
53471
+ const handleAdvance = useCallback(() => {
53472
+ if (advanceEvent) {
53473
+ eventBus.emit(`UI:${advanceEvent}`, {});
53474
+ }
53475
+ }, [advanceEvent, eventBus]);
53476
+ const handleRestart = useCallback(() => {
53477
+ if (restartEvent) {
53478
+ eventBus.emit(`UI:${restartEvent}`, {});
53479
+ }
53480
+ }, [restartEvent, eventBus]);
53481
+ if (!currentNode) {
53482
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("visual-novel-board relative min-h-[600px] bg-background items-center justify-center", className), gap: "lg", children: [
53483
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", color: "muted", children: "No dialogue nodes" }),
53484
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleRestart, children: "Restart" })
53485
+ ] });
53486
+ }
53487
+ return /* @__PURE__ */ jsx(Box, { className: cn("visual-novel-board relative min-h-[600px] bg-background overflow-hidden", className), children: /* @__PURE__ */ jsx(
53488
+ DialogueBox,
53489
+ {
53490
+ dialogue: {
53491
+ speaker: currentNode.speaker,
53492
+ text: currentNode.text,
53493
+ choices: dialogueChoices
53494
+ },
53495
+ typewriterSpeed,
53496
+ position: "bottom",
53497
+ backgroundImage,
53498
+ portraitUrl,
53499
+ portraitScale,
53500
+ onChoice: handleChoice,
53501
+ onAdvance: handleAdvance
53502
+ }
53503
+ ) });
53504
+ }
53505
+ var DEFAULT_NODES;
53506
+ var init_VisualNovelBoard = __esm({
53507
+ "components/game/organisms/VisualNovelBoard.tsx"() {
53508
+ "use client";
53509
+ init_cn();
53510
+ init_useEventBus();
53511
+ init_Box();
53512
+ init_Typography();
53513
+ init_Stack();
53514
+ init_Button();
53515
+ init_DialogueBox();
53516
+ init_boardEntity();
53517
+ DEFAULT_NODES = [
53518
+ {
53519
+ id: "start",
53520
+ speaker: "Narrator",
53521
+ text: "The corridor stretches into shadow. A lone sentinel blocks your path.",
53522
+ backgroundKey: "corridor",
53523
+ portraitKey: "guide",
53524
+ choices: [
53525
+ { label: "Approach the sentinel.", nextId: "meet" },
53526
+ { label: "Turn back.", nextId: "retreat" }
53527
+ ]
53528
+ },
53529
+ {
53530
+ id: "meet",
53531
+ speaker: "Sentinel",
53532
+ text: "You carry the old marks. Speak your purpose, traveler.",
53533
+ backgroundKey: "forge",
53534
+ portraitKey: "rival",
53535
+ choices: [
53536
+ { label: "I seek the core.", nextId: "end" },
53537
+ { label: "I am only passing through.", nextId: "retreat" }
53538
+ ]
53539
+ },
53540
+ {
53541
+ id: "retreat",
53542
+ speaker: "Narrator",
53543
+ text: "You withdraw into the dark. The path will wait for braver feet.",
53544
+ backgroundKey: "corridor",
53545
+ choices: [{ label: "Begin again.", nextId: "start" }]
53546
+ },
53547
+ {
53548
+ id: "end",
53549
+ speaker: "Sentinel",
53550
+ text: "Then the way is open. Walk it well.",
53551
+ backgroundKey: "core",
53552
+ portraitKey: "rival",
53553
+ choices: [{ label: "Begin again.", nextId: "start" }]
53554
+ }
53555
+ ];
53556
+ VisualNovelBoard.displayName = "VisualNovelBoard";
53557
+ }
53558
+ });
53559
+ function VisualNovelTemplate({
53560
+ entity,
53561
+ title = "Visual Novel",
53562
+ nodes,
53563
+ currentNodeId,
53564
+ typewriterSpeed,
53565
+ portraitScale,
53566
+ chooseEvent,
53567
+ advanceEvent,
53568
+ restartEvent,
53569
+ className
53570
+ }) {
53571
+ const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
53572
+ return /* @__PURE__ */ jsxs(
53573
+ Box,
53574
+ {
53575
+ display: "flex",
53576
+ fullHeight: true,
53577
+ className: cn("visual-novel-template flex-col", className),
53578
+ children: [
53579
+ /* @__PURE__ */ jsx(
53580
+ HStack,
53581
+ {
53582
+ gap: "sm",
53583
+ align: "center",
53584
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
53585
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
53586
+ }
53587
+ ),
53588
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
53589
+ VisualNovelBoard,
53590
+ {
53591
+ entity: resolved,
53592
+ nodes,
53593
+ currentNodeId,
53594
+ typewriterSpeed,
53595
+ portraitScale,
53596
+ chooseEvent,
53597
+ advanceEvent,
53598
+ restartEvent,
53599
+ className: "h-full"
53600
+ }
53601
+ ) })
53602
+ ]
53603
+ }
53604
+ );
53605
+ }
53606
+ var init_VisualNovelTemplate = __esm({
53607
+ "components/game/templates/VisualNovelTemplate.tsx"() {
53608
+ init_cn();
53609
+ init_Box();
53610
+ init_Stack();
53611
+ init_Typography();
53612
+ init_VisualNovelBoard();
53613
+ VisualNovelTemplate.displayName = "VisualNovelTemplate";
53614
+ }
53615
+ });
52217
53616
  function heroPosition(h) {
52218
53617
  if ("position" in h && h.position != null) return h.position;
52219
53618
  return vec2(h.position);
@@ -52554,48 +53953,48 @@ function WorldMapTemplate({
52554
53953
  }
52555
53954
  );
52556
53955
  }
52557
- var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
53956
+ var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
52558
53957
  var init_WorldMapTemplate = __esm({
52559
53958
  "components/game/templates/WorldMapTemplate.tsx"() {
52560
53959
  init_WorldMapBoard();
52561
- CDN7 = "https://almadar-kflow-assets.web.app/shared";
53960
+ CDN5 = "https://almadar-kflow-assets.web.app/shared";
52562
53961
  DEFAULT_WORLDMAP_TILES = [
52563
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52564
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52565
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52566
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52567
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52568
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52569
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52570
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52571
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52572
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52573
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52574
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52575
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
52576
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52577
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52578
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52579
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52580
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52581
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
52582
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52583
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52584
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52585
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52586
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52587
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
53962
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53963
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53964
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53965
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53966
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53967
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53968
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53969
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53970
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53971
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53972
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53973
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53974
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53975
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53976
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53977
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53978
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53979
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53980
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53981
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53982
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53983
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53984
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53985
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53986
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
52588
53987
  ];
52589
53988
  DEFAULT_WORLDMAP_UNITS = [
52590
- { 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` },
52591
- { 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` }
53989
+ { 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` },
53990
+ { 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` }
52592
53991
  ];
52593
53992
  DEFAULT_WORLDMAP_FEATURES = [
52594
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
52595
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
53993
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
53994
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
52596
53995
  ];
52597
53996
  DEFAULT_WORLDMAP_MANIFEST = {
52598
- baseUrl: CDN7,
53997
+ baseUrl: CDN5,
52599
53998
  terrains: {
52600
53999
  grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
52601
54000
  water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
@@ -52615,7 +54014,7 @@ var init_WorldMapTemplate = __esm({
52615
54014
  }
52616
54015
  });
52617
54016
  function lazyThree(name, loader) {
52618
- const Lazy = React90__default.lazy(
54017
+ const Lazy = React93__default.lazy(
52619
54018
  () => loader().then((m) => {
52620
54019
  const Resolved = m[name];
52621
54020
  if (!Resolved) {
@@ -52627,13 +54026,13 @@ function lazyThree(name, loader) {
52627
54026
  })
52628
54027
  );
52629
54028
  function ThreeWrapper(props) {
52630
- return React90__default.createElement(
54029
+ return React93__default.createElement(
52631
54030
  ThreeBoundary,
52632
54031
  { name },
52633
- React90__default.createElement(
52634
- React90__default.Suspense,
54032
+ React93__default.createElement(
54033
+ React93__default.Suspense,
52635
54034
  { fallback: null },
52636
- React90__default.createElement(Lazy, props)
54035
+ React93__default.createElement(Lazy, props)
52637
54036
  )
52638
54037
  );
52639
54038
  }
@@ -52677,7 +54076,10 @@ var init_component_registry_generated = __esm({
52677
54076
  init_CalendarGrid();
52678
54077
  init_CanvasEffect();
52679
54078
  init_Card();
54079
+ init_CardBattlerBoard();
54080
+ init_CardBattlerTemplate();
52680
54081
  init_CardGrid();
54082
+ init_CardHand();
52681
54083
  init_Carousel();
52682
54084
  init_CaseStudyCard();
52683
54085
  init_CaseStudyOrganism();
@@ -52688,6 +54090,8 @@ var init_component_registry_generated = __esm({
52688
54090
  init_ChartLegend();
52689
54091
  init_Checkbox();
52690
54092
  init_ChoiceButton();
54093
+ init_CityBuilderBoard();
54094
+ init_CityBuilderTemplate();
52691
54095
  init_ClassifierBoard();
52692
54096
  init_CodeBlock();
52693
54097
  init_CodeRunnerPanel();
@@ -52908,6 +54312,8 @@ var init_component_registry_generated = __esm({
52908
54312
  init_Toast();
52909
54313
  init_ToastSlot();
52910
54314
  init_Tooltip();
54315
+ init_TopDownShooterBoard();
54316
+ init_TopDownShooterTemplate();
52911
54317
  init_TowerDefenseBoard();
52912
54318
  init_TowerDefenseTemplate();
52913
54319
  init_TraitFrame();
@@ -52923,6 +54329,8 @@ var init_component_registry_generated = __esm({
52923
54329
  init_UploadDropZone();
52924
54330
  init_VersionDiff();
52925
54331
  init_ViolationAlert();
54332
+ init_VisualNovelBoard();
54333
+ init_VisualNovelTemplate();
52926
54334
  init_VoteStack();
52927
54335
  init_WaypointMarker();
52928
54336
  init_WizardContainer();
@@ -52931,7 +54339,7 @@ var init_component_registry_generated = __esm({
52931
54339
  init_WorldMapBoard();
52932
54340
  init_WorldMapTemplate();
52933
54341
  init_XPBar();
52934
- ThreeBoundary = class extends React90__default.Component {
54342
+ ThreeBoundary = class extends React93__default.Component {
52935
54343
  constructor() {
52936
54344
  super(...arguments);
52937
54345
  __publicField(this, "state", { failed: false });
@@ -52941,7 +54349,7 @@ var init_component_registry_generated = __esm({
52941
54349
  }
52942
54350
  render() {
52943
54351
  if (this.state.failed) {
52944
- return React90__default.createElement(
54352
+ return React93__default.createElement(
52945
54353
  "div",
52946
54354
  {
52947
54355
  "data-testid": "three-unavailable",
@@ -52997,7 +54405,10 @@ var init_component_registry_generated = __esm({
52997
54405
  "CalendarGrid": CalendarGrid,
52998
54406
  "CanvasEffect": CanvasEffect,
52999
54407
  "Card": Card,
54408
+ "CardBattlerBoard": CardBattlerBoard,
54409
+ "CardBattlerTemplate": CardBattlerTemplate,
53000
54410
  "CardGrid": CardGrid,
54411
+ "CardHand": CardHand,
53001
54412
  "Carousel": Carousel,
53002
54413
  "CaseStudyCard": CaseStudyCard,
53003
54414
  "CaseStudyOrganism": CaseStudyOrganism,
@@ -53008,6 +54419,8 @@ var init_component_registry_generated = __esm({
53008
54419
  "ChartLegend": ChartLegend,
53009
54420
  "Checkbox": Checkbox,
53010
54421
  "ChoiceButton": ChoiceButton,
54422
+ "CityBuilderBoard": CityBuilderBoard,
54423
+ "CityBuilderTemplate": CityBuilderTemplate,
53011
54424
  "ClassifierBoard": ClassifierBoard,
53012
54425
  "CodeBlock": CodeBlock,
53013
54426
  "CodeRunnerPanel": CodeRunnerPanel,
@@ -53240,6 +54653,8 @@ var init_component_registry_generated = __esm({
53240
54653
  "Toast": Toast,
53241
54654
  "ToastSlot": ToastSlot,
53242
54655
  "Tooltip": Tooltip,
54656
+ "TopDownShooterBoard": TopDownShooterBoard,
54657
+ "TopDownShooterTemplate": TopDownShooterTemplate,
53243
54658
  "TowerDefenseBoard": TowerDefenseBoard,
53244
54659
  "TowerDefenseTemplate": TowerDefenseTemplate,
53245
54660
  "TraitFrame": TraitFrame,
@@ -53256,6 +54671,8 @@ var init_component_registry_generated = __esm({
53256
54671
  "VStack": VStack,
53257
54672
  "VersionDiff": VersionDiff,
53258
54673
  "ViolationAlert": ViolationAlert,
54674
+ "VisualNovelBoard": VisualNovelBoard,
54675
+ "VisualNovelTemplate": VisualNovelTemplate,
53259
54676
  "VoteStack": VoteStack,
53260
54677
  "WaypointMarker": WaypointMarker,
53261
54678
  "WizardContainer": WizardContainer,
@@ -53282,7 +54699,7 @@ function SuspenseConfigProvider({
53282
54699
  config,
53283
54700
  children
53284
54701
  }) {
53285
- return React90__default.createElement(
54702
+ return React93__default.createElement(
53286
54703
  SuspenseConfigContext.Provider,
53287
54704
  { value: config },
53288
54705
  children
@@ -53772,7 +55189,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
53772
55189
  const key = `${parentId}-${index}-trait:${traitName}`;
53773
55190
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
53774
55191
  }
53775
- return /* @__PURE__ */ jsx(React90__default.Fragment, { children: child }, `${parentId}-${index}`);
55192
+ return /* @__PURE__ */ jsx(React93__default.Fragment, { children: child }, `${parentId}-${index}`);
53776
55193
  }
53777
55194
  if (!child || typeof child !== "object") return null;
53778
55195
  const childId = `${parentId}-${index}`;
@@ -53812,14 +55229,14 @@ function isPatternConfig(value) {
53812
55229
  if (value === null || value === void 0) return false;
53813
55230
  if (typeof value !== "object") return false;
53814
55231
  if (Array.isArray(value)) return false;
53815
- if (React90__default.isValidElement(value)) return false;
55232
+ if (React93__default.isValidElement(value)) return false;
53816
55233
  if (value instanceof Date) return false;
53817
55234
  if (typeof value === "function") return false;
53818
55235
  const record = value;
53819
55236
  return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
53820
55237
  }
53821
55238
  function isPlainConfigObject(value) {
53822
- if (React90__default.isValidElement(value)) return false;
55239
+ if (React93__default.isValidElement(value)) return false;
53823
55240
  if (value instanceof Date) return false;
53824
55241
  const proto = Object.getPrototypeOf(value);
53825
55242
  return proto === Object.prototype || proto === null;
@@ -53940,6 +55357,22 @@ function SlotContentRenderer({
53940
55357
  const childrenIsRenderFn = typeof incomingChildren === "function";
53941
55358
  const { children: _childrenConfig, ...restPropsNoChildren } = content.props;
53942
55359
  const restProps = childrenIsRenderFn ? { ...restPropsNoChildren, children: incomingChildren } : restPropsNoChildren;
55360
+ const nodeSlotOverrides = {};
55361
+ for (const slotKey of CONTENT_NODE_SLOTS) {
55362
+ const slotVal = restProps[slotKey];
55363
+ if (slotVal === void 0 || slotVal === null) continue;
55364
+ if (React93__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
55365
+ if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
55366
+ nodeSlotOverrides[slotKey] = renderPatternChildren(
55367
+ slotVal,
55368
+ onDismiss,
55369
+ `${content.id}-${slotKey}`,
55370
+ `${myPath}.${slotKey}`,
55371
+ content.sourceTrait,
55372
+ { slot: content.slot, transitionEvent: content.transitionEvent, fromState: content.fromState, entity: content.entity }
55373
+ );
55374
+ }
55375
+ }
53943
55376
  const renderedProps = renderPatternProps(restProps, onDismiss);
53944
55377
  const patternDef = getPatternDefinition(content.pattern);
53945
55378
  const propsSchema = patternDef?.propsSchema;
@@ -53970,6 +55403,9 @@ function SlotContentRenderer({
53970
55403
  }
53971
55404
  }
53972
55405
  const finalProps = renderedProps;
55406
+ for (const [k, v] of Object.entries(nodeSlotOverrides)) {
55407
+ finalProps[k] = v;
55408
+ }
53973
55409
  const resolvedItems = Array.isArray(
53974
55410
  finalProps.entity
53975
55411
  ) ? finalProps.entity : null;
@@ -54090,7 +55526,7 @@ function UISlotRenderer({
54090
55526
  }
54091
55527
  return wrapped;
54092
55528
  }
54093
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, FORM_PATTERNS, SELF_OVERLAY_PATTERNS, PATTERNS_WITH_CHILDREN;
55529
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, FORM_PATTERNS, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
54094
55530
  var init_UISlotRenderer = __esm({
54095
55531
  "components/core/organisms/UISlotRenderer.tsx"() {
54096
55532
  "use client";
@@ -54127,6 +55563,16 @@ var init_UISlotRenderer = __esm({
54127
55563
  "wizard-step"
54128
55564
  ]);
54129
55565
  SELF_OVERLAY_PATTERNS = /* @__PURE__ */ new Set(["modal", "confirm-dialog"]);
55566
+ CONTENT_NODE_SLOTS = /* @__PURE__ */ new Set([
55567
+ "logo",
55568
+ "master",
55569
+ "detail",
55570
+ "trigger",
55571
+ "content",
55572
+ "addons",
55573
+ "hud",
55574
+ "fallback"
55575
+ ]);
54130
55576
  PATTERNS_WITH_CHILDREN = /* @__PURE__ */ new Set([
54131
55577
  "stack",
54132
55578
  "vstack",
@@ -54326,7 +55772,7 @@ var AvlTransition = ({
54326
55772
  opacity = 1,
54327
55773
  className
54328
55774
  }) => {
54329
- const ids = React90__default.useMemo(() => {
55775
+ const ids = React93__default.useMemo(() => {
54330
55776
  avlTransitionId += 1;
54331
55777
  return { arrow: `avl-tr-${avlTransitionId}-arrow` };
54332
55778
  }, []);
@@ -54887,7 +56333,7 @@ var AvlStateMachine = ({
54887
56333
  color = "var(--color-primary)",
54888
56334
  animated = false
54889
56335
  }) => {
54890
- const ids = React90__default.useMemo(() => {
56336
+ const ids = React93__default.useMemo(() => {
54891
56337
  avlSmId += 1;
54892
56338
  const base = `avl-sm-${avlSmId}`;
54893
56339
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -55086,7 +56532,7 @@ var AvlOrbitalUnit = ({
55086
56532
  color = "var(--color-primary)",
55087
56533
  animated = false
55088
56534
  }) => {
55089
- const ids = React90__default.useMemo(() => {
56535
+ const ids = React93__default.useMemo(() => {
55090
56536
  avlOuId += 1;
55091
56537
  const base = `avl-ou-${avlOuId}`;
55092
56538
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -55182,7 +56628,7 @@ var AvlClosedCircuit = ({
55182
56628
  color = "var(--color-primary)",
55183
56629
  animated = false
55184
56630
  }) => {
55185
- const ids = React90__default.useMemo(() => {
56631
+ const ids = React93__default.useMemo(() => {
55186
56632
  avlCcId += 1;
55187
56633
  const base = `avl-cc-${avlCcId}`;
55188
56634
  return { glow: `${base}-glow`, grad: `${base}-grad`, arrow: `${base}-arrow` };
@@ -55337,7 +56783,7 @@ var AvlEmitListen = ({
55337
56783
  color = "var(--color-primary)",
55338
56784
  animated = false
55339
56785
  }) => {
55340
- const ids = React90__default.useMemo(() => {
56786
+ const ids = React93__default.useMemo(() => {
55341
56787
  avlElId += 1;
55342
56788
  const base = `avl-el-${avlElId}`;
55343
56789
  return { arrow: `${base}-arrow`, grad: `${base}-grad` };
@@ -55611,7 +57057,7 @@ function renderNode(node, color, glowId) {
55611
57057
  const baseR = node.type === "operator" ? 20 : 16;
55612
57058
  const r2 = Math.max(baseR, labelLen * 3.5 + 6);
55613
57059
  const nc = nodeColor(node.type, color);
55614
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
57060
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
55615
57061
  node.children.map((child, i) => {
55616
57062
  const childR = Math.max(
55617
57063
  child.type === "operator" ? 20 : 16,
@@ -55668,7 +57114,7 @@ var AvlExprTree = ({
55668
57114
  className,
55669
57115
  color = "var(--color-primary)"
55670
57116
  }) => {
55671
- const ids = React90__default.useMemo(() => {
57117
+ const ids = React93__default.useMemo(() => {
55672
57118
  avlEtId += 1;
55673
57119
  return { glow: `avl-et-${avlEtId}-glow` };
55674
57120
  }, []);
@@ -56492,7 +57938,7 @@ var SystemNode = ({ data }) => {
56492
57938
  stateChain.length > 0 && /* @__PURE__ */ jsx("svg", { width: stateChain.length * 14 + 2, height: 10, viewBox: `0 0 ${stateChain.length * 14 + 2} 10`, children: stateChain.map((s, i) => {
56493
57939
  const tc = transitionCounts[s.name] ?? 0;
56494
57940
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
56495
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
57941
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
56496
57942
  /* @__PURE__ */ jsx(AvlState, { x: i * 14 + 1, y: 1, width: 10, height: 8, name: "", role, isInitial: s.isInitial, isTerminal: s.isTerminal }),
56497
57943
  i < stateChain.length - 1 && /* @__PURE__ */ jsx("line", { x1: i * 14 + 12, y1: 5, x2: i * 14 + 15, y2: 5, stroke: "var(--color-border)", strokeWidth: 0.5 })
56498
57944
  ] }, s.name);
@@ -57644,7 +59090,7 @@ function resolveLambdaBindings(body, params, item, index) {
57644
59090
  if (Array.isArray(body)) {
57645
59091
  return body.map((b) => recur(b));
57646
59092
  }
57647
- if (body !== null && typeof body === "object" && !React90__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
59093
+ if (body !== null && typeof body === "object" && !React93__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
57648
59094
  const out = {};
57649
59095
  for (const [k, v] of Object.entries(body)) {
57650
59096
  out[k] = recur(v);
@@ -57663,7 +59109,7 @@ function getSlotContentRenderer2() {
57663
59109
  function makeLambdaFn(params, lambdaBody, callerKey) {
57664
59110
  return (item, index) => {
57665
59111
  const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
57666
- if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React90__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
59112
+ if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React93__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
57667
59113
  return null;
57668
59114
  }
57669
59115
  const record = resolvedBody;
@@ -57682,7 +59128,7 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
57682
59128
  props: childProps,
57683
59129
  priority: 0
57684
59130
  };
57685
- return React90__default.createElement(SlotContentRenderer2, { content: childContent });
59131
+ return React93__default.createElement(SlotContentRenderer2, { content: childContent });
57686
59132
  };
57687
59133
  }
57688
59134
  function convertNode(node, callerKey) {
@@ -57701,7 +59147,7 @@ function convertNode(node, callerKey) {
57701
59147
  });
57702
59148
  return anyChanged ? mapped : node;
57703
59149
  }
57704
- if (typeof node === "object" && !React90__default.isValidElement(node) && !(node instanceof Date)) {
59150
+ if (typeof node === "object" && !React93__default.isValidElement(node) && !(node instanceof Date)) {
57705
59151
  return convertObjectProps(node);
57706
59152
  }
57707
59153
  return node;
@@ -59933,8 +61379,8 @@ function CanvasDndProvider({
59933
61379
  }) {
59934
61380
  const eventBus = useEventBus();
59935
61381
  const sensors = useAlmadarDndSensors(false);
59936
- const [activePayload, setActivePayload] = React90__default.useState(null);
59937
- const handleDragStart = React90__default.useCallback((e) => {
61382
+ const [activePayload, setActivePayload] = React93__default.useState(null);
61383
+ const handleDragStart = React93__default.useCallback((e) => {
59938
61384
  const data = e.active.data.current;
59939
61385
  const payload = data?.payload;
59940
61386
  if (payload) {
@@ -59945,7 +61391,7 @@ function CanvasDndProvider({
59945
61391
  log13.warn("dragStart:missing-payload", { id: e.active.id });
59946
61392
  }
59947
61393
  }, [eventBus]);
59948
- const handleDragEnd = React90__default.useCallback((e) => {
61394
+ const handleDragEnd = React93__default.useCallback((e) => {
59949
61395
  setActivePayload(null);
59950
61396
  const activeData = e.active.data.current;
59951
61397
  const payload = activeData?.payload;
@@ -59974,7 +61420,7 @@ function CanvasDndProvider({
59974
61420
  const suppressed = onDrop ? onDrop(drop) === true : false;
59975
61421
  if (!suppressed) defaultEmit(eventBus, drop);
59976
61422
  }, [eventBus, onDrop]);
59977
- const handleDragCancel = React90__default.useCallback(() => {
61423
+ const handleDragCancel = React93__default.useCallback(() => {
59978
61424
  setActivePayload(null);
59979
61425
  log13.info("dragCancel");
59980
61426
  }, []);
@@ -60728,7 +62174,7 @@ var OrbPreviewNodeInner = (props) => {
60728
62174
  }
60729
62175
  );
60730
62176
  };
60731
- var OrbPreviewNode = React90__default.memo(OrbPreviewNodeInner);
62177
+ var OrbPreviewNode = React93__default.memo(OrbPreviewNodeInner);
60732
62178
  OrbPreviewNode.displayName = "OrbPreviewNode";
60733
62179
  orbPreviewLog.debug("export-resolved", () => ({
60734
62180
  type: typeof OrbPreviewNode,
@@ -60833,7 +62279,7 @@ var EventFlowEdgeInner = (props) => {
60833
62279
  ) })
60834
62280
  ] });
60835
62281
  };
60836
- var EventFlowEdge = React90__default.memo(EventFlowEdgeInner);
62282
+ var EventFlowEdge = React93__default.memo(EventFlowEdgeInner);
60837
62283
  EventFlowEdge.displayName = "EventFlowEdge";
60838
62284
 
60839
62285
  // components/avl/molecules/BehaviorComposeNode.tsx
@@ -60980,7 +62426,7 @@ var BehaviorComposeNodeInner = (props) => {
60980
62426
  }
60981
62427
  );
60982
62428
  };
60983
- var BehaviorComposeNode = React90__default.memo(BehaviorComposeNodeInner);
62429
+ var BehaviorComposeNode = React93__default.memo(BehaviorComposeNodeInner);
60984
62430
  BehaviorComposeNode.displayName = "BehaviorComposeNode";
60985
62431
 
60986
62432
  // components/avl/molecules/avl-behavior-compose-converter.ts
@@ -61992,7 +63438,7 @@ var TraitCardNodeInner = (props) => {
61992
63438
  }
61993
63439
  );
61994
63440
  };
61995
- var TraitCardNode = React90__default.memo(TraitCardNodeInner);
63441
+ var TraitCardNode = React93__default.memo(TraitCardNodeInner);
61996
63442
  TraitCardNode.displayName = "TraitCardNode";
61997
63443
 
61998
63444
  // components/avl/organisms/FlowCanvas.tsx
@@ -62065,7 +63511,7 @@ function FlowCanvasInner({
62065
63511
  initialOrbital
62066
63512
  );
62067
63513
  const [expandedBehaviorAlias, setExpandedBehaviorAlias] = useState(void 0);
62068
- const screenSizeUserOverrideRef = React90__default.useRef(false);
63514
+ const screenSizeUserOverrideRef = React93__default.useRef(false);
62069
63515
  const [screenSize, setScreenSize] = useState(
62070
63516
  () => typeof window === "undefined" ? "laptop" : detectScreenSize(window.innerWidth)
62071
63517
  );
@@ -62449,7 +63895,7 @@ var ZoomBreadcrumb = ({
62449
63895
  if (eventName && band === "detail") {
62450
63896
  segments.push({ icon: "\u26A1", label: eventName });
62451
63897
  }
62452
- return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
63898
+ return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
62453
63899
  i > 0 && /* @__PURE__ */ jsx("span", { className: "opacity-40", children: ">" }),
62454
63900
  /* @__PURE__ */ jsx("span", { className: "opacity-60", children: seg.icon }),
62455
63901
  /* @__PURE__ */ jsx("span", { children: seg.label })
@@ -62790,7 +64236,7 @@ var EventWireOverlay = ({
62790
64236
  containerW,
62791
64237
  containerH
62792
64238
  }) => {
62793
- const ids = React90__default.useMemo(() => {
64239
+ const ids = React93__default.useMemo(() => {
62794
64240
  avlOczWireId += 1;
62795
64241
  return { arrow: `avl-ocz-wire-${avlOczWireId}-arrow` };
62796
64242
  }, []);
@@ -63157,7 +64603,7 @@ var AvlOrbitalsCosmicZoom = ({
63157
64603
  borderRadius: 6,
63158
64604
  border: `1px solid ${color}`
63159
64605
  },
63160
- children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
64606
+ children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
63161
64607
  i > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", style: { opacity: 0.5, color }, children: "/" }),
63162
64608
  i < breadcrumbs.length - 1 ? /* @__PURE__ */ jsx(
63163
64609
  Box,