@almadar/ui 5.71.0 → 5.73.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 (55) hide show
  1. package/dist/avl/index.cjs +2178 -2309
  2. package/dist/avl/index.js +912 -1043
  3. package/dist/components/game/atoms/ActionButton.d.ts +3 -3
  4. package/dist/components/game/atoms/ChoiceButton.d.ts +3 -3
  5. package/dist/components/game/atoms/ComboCounter.d.ts +3 -3
  6. package/dist/components/game/atoms/ControlButton.d.ts +3 -3
  7. package/dist/components/game/atoms/DamageNumber.d.ts +3 -3
  8. package/dist/components/game/atoms/DialogueBubble.d.ts +3 -3
  9. package/dist/components/game/atoms/ItemSlot.d.ts +3 -3
  10. package/dist/components/game/atoms/ResourceCounter.d.ts +3 -3
  11. package/dist/components/game/atoms/ScoreDisplay.d.ts +4 -6
  12. package/dist/components/game/atoms/Sprite.d.ts +9 -21
  13. package/dist/components/game/atoms/StateIndicator.d.ts +2 -2
  14. package/dist/components/game/atoms/StatusEffect.d.ts +3 -3
  15. package/dist/components/game/atoms/TurnIndicator.d.ts +3 -3
  16. package/dist/components/game/atoms/WaypointMarker.d.ts +3 -3
  17. package/dist/components/game/atoms/XPBar.d.ts +1 -1
  18. package/dist/components/game/molecules/CardHand.d.ts +2 -2
  19. package/dist/components/game/molecules/DialogueBox.d.ts +3 -3
  20. package/dist/components/game/molecules/EnemyPlate.d.ts +3 -3
  21. package/dist/components/game/molecules/GameCanvas2D.d.ts +3 -3
  22. package/dist/components/game/molecules/GameCanvas3D.d.ts +0 -2
  23. package/dist/components/game/molecules/HealthPanel.d.ts +3 -3
  24. package/dist/components/game/molecules/IsometricCanvas.d.ts +11 -13
  25. package/dist/components/game/molecules/PlatformerCanvas.d.ts +4 -1
  26. package/dist/components/game/molecules/PowerupSlots.d.ts +3 -3
  27. package/dist/components/game/molecules/StatBadge.d.ts +6 -4
  28. package/dist/components/game/molecules/TurnPanel.d.ts +3 -3
  29. package/dist/components/game/molecules/three/index.cjs +55 -109
  30. package/dist/components/game/molecules/three/index.js +55 -109
  31. package/dist/components/game/molecules/useUnitSpriteAtlas.d.ts +6 -12
  32. package/dist/components/game/organisms/BattleBoard.d.ts +5 -6
  33. package/dist/components/game/organisms/CardBattlerBoard.d.ts +3 -4
  34. package/dist/components/game/organisms/CastleBoard.d.ts +5 -6
  35. package/dist/components/game/organisms/CityBuilderBoard.d.ts +6 -7
  36. package/dist/components/game/organisms/FishingBoard.d.ts +4 -6
  37. package/dist/components/game/organisms/PlatformerBoard.d.ts +5 -5
  38. package/dist/components/game/organisms/RoguelikeBoard.d.ts +4 -5
  39. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +5 -6
  40. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +5 -6
  41. package/dist/components/game/organisms/VisualNovelBoard.d.ts +4 -5
  42. package/dist/components/game/organisms/WorldMapBoard.d.ts +5 -6
  43. package/dist/components/game/organisms/types/effects.d.ts +7 -8
  44. package/dist/components/game/organisms/types/isometric.d.ts +24 -8
  45. package/dist/components/game/organisms/types/spriteAnimation.d.ts +3 -4
  46. package/dist/components/game/organisms/utils/makeAsset.d.ts +5 -0
  47. package/dist/components/game/templates/PlatformerTemplate.d.ts +5 -4
  48. package/dist/components/game/templates/game3dAssetManifest.d.ts +6 -8
  49. package/dist/components/index.cjs +2314 -2411
  50. package/dist/components/index.js +1203 -1300
  51. package/dist/providers/index.cjs +1987 -2118
  52. package/dist/providers/index.js +888 -1019
  53. package/dist/runtime/index.cjs +2043 -2174
  54. package/dist/runtime/index.js +892 -1023
  55. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
- import * as React90 from 'react';
2
- import React90__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useLayoutEffect, lazy, useId, useSyncExternalStore, forwardRef, useImperativeHandle, Component } from 'react';
1
+ import * as React88 from 'react';
2
+ import React88__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useLayoutEffect, lazy, useId, useSyncExternalStore, forwardRef, useImperativeHandle, Component } from 'react';
3
3
  import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
4
4
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -403,7 +403,7 @@ var init_Box = __esm({
403
403
  fixed: "fixed",
404
404
  sticky: "sticky"
405
405
  };
406
- Box = React90__default.forwardRef(
406
+ Box = React88__default.forwardRef(
407
407
  ({
408
408
  padding,
409
409
  paddingX,
@@ -468,7 +468,7 @@ var init_Box = __esm({
468
468
  onPointerDown?.(e);
469
469
  }, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
470
470
  const isClickable = action || onClick;
471
- return React90__default.createElement(
471
+ return React88__default.createElement(
472
472
  Component2,
473
473
  {
474
474
  ref,
@@ -564,7 +564,7 @@ function loadLib(key, importer) {
564
564
  return p2;
565
565
  }
566
566
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
567
- const Lazy = React90__default.lazy(async () => {
567
+ const Lazy = React88__default.lazy(async () => {
568
568
  const lib = await loadLib(libKey, importer);
569
569
  const Comp = pick(lib);
570
570
  if (!Comp) {
@@ -574,7 +574,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
574
574
  return { default: Comp };
575
575
  });
576
576
  const Wrapped = (props) => /* @__PURE__ */ jsx(
577
- React90__default.Suspense,
577
+ React88__default.Suspense,
578
578
  {
579
579
  fallback: /* @__PURE__ */ jsx(
580
580
  "span",
@@ -1301,7 +1301,7 @@ var init_Icon = __esm({
1301
1301
  const directIcon = typeof icon === "string" ? void 0 : icon;
1302
1302
  const effectiveName = typeof icon === "string" ? icon : name;
1303
1303
  const family = useIconFamily();
1304
- const RenderedComponent = React90__default.useMemo(() => {
1304
+ const RenderedComponent = React88__default.useMemo(() => {
1305
1305
  if (directIcon) return null;
1306
1306
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
1307
1307
  }, [directIcon, effectiveName, family]);
@@ -1363,7 +1363,7 @@ function resolveIconProp(value, sizeClass) {
1363
1363
  const IconComp = value;
1364
1364
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
1365
1365
  }
1366
- if (React90__default.isValidElement(value)) {
1366
+ if (React88__default.isValidElement(value)) {
1367
1367
  return value;
1368
1368
  }
1369
1369
  if (typeof value === "object" && value !== null && isIconLike(value)) {
@@ -1439,7 +1439,7 @@ var init_Button = __esm({
1439
1439
  md: "h-icon-default w-icon-default",
1440
1440
  lg: "h-icon-default w-icon-default"
1441
1441
  };
1442
- Button = React90__default.forwardRef(
1442
+ Button = React88__default.forwardRef(
1443
1443
  ({
1444
1444
  className,
1445
1445
  variant = "primary",
@@ -1505,7 +1505,7 @@ var Dialog;
1505
1505
  var init_Dialog = __esm({
1506
1506
  "components/core/atoms/Dialog.tsx"() {
1507
1507
  init_cn();
1508
- Dialog = React90__default.forwardRef(
1508
+ Dialog = React88__default.forwardRef(
1509
1509
  ({
1510
1510
  role = "dialog",
1511
1511
  "aria-modal": ariaModal = true,
@@ -1623,7 +1623,7 @@ var init_Typography = __esm({
1623
1623
  }) => {
1624
1624
  const variant = variantProp ?? (level ? `h${level}` : "body1");
1625
1625
  const Component2 = as || defaultElements[variant];
1626
- return React90__default.createElement(
1626
+ return React88__default.createElement(
1627
1627
  Component2,
1628
1628
  {
1629
1629
  id,
@@ -2118,7 +2118,7 @@ var init_Badge = __esm({
2118
2118
  md: "px-2.5 py-1 text-sm",
2119
2119
  lg: "px-3 py-1.5 text-base"
2120
2120
  };
2121
- Badge = React90__default.forwardRef(
2121
+ Badge = React88__default.forwardRef(
2122
2122
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
2123
2123
  const iconSizes3 = {
2124
2124
  sm: "h-icon-default w-icon-default",
@@ -2454,7 +2454,7 @@ var init_SvgFlow = __esm({
2454
2454
  width = 100,
2455
2455
  height = 100
2456
2456
  }) => {
2457
- const markerId = React90__default.useMemo(() => {
2457
+ const markerId = React88__default.useMemo(() => {
2458
2458
  flowIdCounter += 1;
2459
2459
  return `almadar-flow-arrow-${flowIdCounter}`;
2460
2460
  }, []);
@@ -3047,7 +3047,7 @@ var init_SvgRing = __esm({
3047
3047
  width = 100,
3048
3048
  height = 100
3049
3049
  }) => {
3050
- const gradientId = React90__default.useMemo(() => {
3050
+ const gradientId = React88__default.useMemo(() => {
3051
3051
  ringIdCounter += 1;
3052
3052
  return `almadar-ring-glow-${ringIdCounter}`;
3053
3053
  }, []);
@@ -3228,7 +3228,7 @@ var init_Input = __esm({
3228
3228
  init_cn();
3229
3229
  init_Icon();
3230
3230
  init_useEventBus();
3231
- Input = React90__default.forwardRef(
3231
+ Input = React88__default.forwardRef(
3232
3232
  ({
3233
3233
  className,
3234
3234
  inputType,
@@ -3388,7 +3388,7 @@ var Label;
3388
3388
  var init_Label = __esm({
3389
3389
  "components/core/atoms/Label.tsx"() {
3390
3390
  init_cn();
3391
- Label = React90__default.forwardRef(
3391
+ Label = React88__default.forwardRef(
3392
3392
  ({ className, required, children, ...props }, ref) => {
3393
3393
  return /* @__PURE__ */ jsxs(
3394
3394
  "label",
@@ -3415,7 +3415,7 @@ var init_Textarea = __esm({
3415
3415
  "components/core/atoms/Textarea.tsx"() {
3416
3416
  init_cn();
3417
3417
  init_useEventBus();
3418
- Textarea = React90__default.forwardRef(
3418
+ Textarea = React88__default.forwardRef(
3419
3419
  ({ className, error, onChange, ...props }, ref) => {
3420
3420
  const eventBus = useEventBus();
3421
3421
  const handleChange = (e) => {
@@ -3654,7 +3654,7 @@ var init_Select = __esm({
3654
3654
  init_cn();
3655
3655
  init_Icon();
3656
3656
  init_useEventBus();
3657
- Select = React90__default.forwardRef(
3657
+ Select = React88__default.forwardRef(
3658
3658
  (props, _ref) => {
3659
3659
  const { multiple, searchable, clearable } = props;
3660
3660
  if (multiple || searchable || clearable) {
@@ -3671,7 +3671,7 @@ var init_Checkbox = __esm({
3671
3671
  "components/core/atoms/Checkbox.tsx"() {
3672
3672
  init_cn();
3673
3673
  init_useEventBus();
3674
- Checkbox = React90__default.forwardRef(
3674
+ Checkbox = React88__default.forwardRef(
3675
3675
  ({ className, label, id, onChange, ...props }, ref) => {
3676
3676
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
3677
3677
  const eventBus = useEventBus();
@@ -3725,7 +3725,7 @@ var init_Spinner = __esm({
3725
3725
  md: "h-6 w-6",
3726
3726
  lg: "h-8 w-8"
3727
3727
  };
3728
- Spinner = React90__default.forwardRef(
3728
+ Spinner = React88__default.forwardRef(
3729
3729
  ({ className, size = "md", overlay, ...props }, ref) => {
3730
3730
  if (overlay) {
3731
3731
  return /* @__PURE__ */ jsx(
@@ -3815,7 +3815,7 @@ var init_Card = __esm({
3815
3815
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
3816
3816
  "tile-image-first": "p-0 overflow-hidden"
3817
3817
  };
3818
- Card = React90__default.forwardRef(
3818
+ Card = React88__default.forwardRef(
3819
3819
  ({
3820
3820
  className,
3821
3821
  variant = "bordered",
@@ -3863,9 +3863,9 @@ var init_Card = __esm({
3863
3863
  }
3864
3864
  );
3865
3865
  Card.displayName = "Card";
3866
- CardHeader = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3866
+ CardHeader = React88__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3867
3867
  CardHeader.displayName = "CardHeader";
3868
- CardTitle = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3868
+ CardTitle = React88__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3869
3869
  "h3",
3870
3870
  {
3871
3871
  ref,
@@ -3878,11 +3878,11 @@ var init_Card = __esm({
3878
3878
  }
3879
3879
  ));
3880
3880
  CardTitle.displayName = "CardTitle";
3881
- CardContent = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3881
+ CardContent = React88__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3882
3882
  CardContent.displayName = "CardContent";
3883
3883
  CardBody = CardContent;
3884
3884
  CardBody.displayName = "CardBody";
3885
- CardFooter = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3885
+ CardFooter = React88__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3886
3886
  "div",
3887
3887
  {
3888
3888
  ref,
@@ -3937,7 +3937,7 @@ var init_FilterPill = __esm({
3937
3937
  md: "w-3.5 h-3.5",
3938
3938
  lg: "w-4 h-4"
3939
3939
  };
3940
- FilterPill = React90__default.forwardRef(
3940
+ FilterPill = React88__default.forwardRef(
3941
3941
  ({
3942
3942
  className,
3943
3943
  variant = "default",
@@ -4066,8 +4066,8 @@ var init_Avatar = __esm({
4066
4066
  actionPayload
4067
4067
  }) => {
4068
4068
  const eventBus = useEventBus();
4069
- const [imgFailed, setImgFailed] = React90__default.useState(false);
4070
- React90__default.useEffect(() => {
4069
+ const [imgFailed, setImgFailed] = React88__default.useState(false);
4070
+ React88__default.useEffect(() => {
4071
4071
  setImgFailed(false);
4072
4072
  }, [src]);
4073
4073
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -4180,7 +4180,7 @@ var init_Center = __esm({
4180
4180
  as: Component2 = "div"
4181
4181
  }) => {
4182
4182
  const mergedStyle = minHeight ? { minHeight, ...style } : style;
4183
- return React90__default.createElement(Component2, {
4183
+ return React88__default.createElement(Component2, {
4184
4184
  className: cn(
4185
4185
  inline ? "inline-flex" : "flex",
4186
4186
  horizontal && "justify-center",
@@ -4448,7 +4448,7 @@ var init_Radio = __esm({
4448
4448
  md: "w-2.5 h-2.5",
4449
4449
  lg: "w-3 h-3"
4450
4450
  };
4451
- Radio = React90__default.forwardRef(
4451
+ Radio = React88__default.forwardRef(
4452
4452
  ({
4453
4453
  label,
4454
4454
  helperText,
@@ -4465,12 +4465,12 @@ var init_Radio = __esm({
4465
4465
  onChange,
4466
4466
  ...props
4467
4467
  }, ref) => {
4468
- const reactId = React90__default.useId();
4468
+ const reactId = React88__default.useId();
4469
4469
  const baseId = id || `radio-${reactId}`;
4470
4470
  const hasError = !!error;
4471
4471
  const eventBus = useEventBus();
4472
- const [selected, setSelected] = React90__default.useState(value);
4473
- React90__default.useEffect(() => {
4472
+ const [selected, setSelected] = React88__default.useState(value);
4473
+ React88__default.useEffect(() => {
4474
4474
  if (value !== void 0) setSelected(value);
4475
4475
  }, [value]);
4476
4476
  const pick = (next, e) => {
@@ -4652,7 +4652,7 @@ var init_Switch = __esm({
4652
4652
  "components/core/atoms/Switch.tsx"() {
4653
4653
  "use client";
4654
4654
  init_cn();
4655
- Switch = React90.forwardRef(
4655
+ Switch = React88.forwardRef(
4656
4656
  ({
4657
4657
  checked,
4658
4658
  defaultChecked = false,
@@ -4663,10 +4663,10 @@ var init_Switch = __esm({
4663
4663
  name,
4664
4664
  className
4665
4665
  }, ref) => {
4666
- const [isChecked, setIsChecked] = React90.useState(
4666
+ const [isChecked, setIsChecked] = React88.useState(
4667
4667
  checked !== void 0 ? checked : defaultChecked
4668
4668
  );
4669
- React90.useEffect(() => {
4669
+ React88.useEffect(() => {
4670
4670
  if (checked !== void 0) {
4671
4671
  setIsChecked(checked);
4672
4672
  }
@@ -4825,7 +4825,7 @@ var init_Stack = __esm({
4825
4825
  };
4826
4826
  const isHorizontal = direction === "horizontal";
4827
4827
  const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
4828
- return React90__default.createElement(
4828
+ return React88__default.createElement(
4829
4829
  Component2,
4830
4830
  {
4831
4831
  className: cn(
@@ -5025,7 +5025,7 @@ var Aside;
5025
5025
  var init_Aside = __esm({
5026
5026
  "components/core/atoms/Aside.tsx"() {
5027
5027
  init_cn();
5028
- Aside = React90__default.forwardRef(
5028
+ Aside = React88__default.forwardRef(
5029
5029
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
5030
5030
  );
5031
5031
  Aside.displayName = "Aside";
@@ -5104,9 +5104,9 @@ var init_LawReferenceTooltip = __esm({
5104
5104
  className
5105
5105
  }) => {
5106
5106
  const { t } = useTranslate();
5107
- const [isVisible, setIsVisible] = React90__default.useState(false);
5108
- const timeoutRef = React90__default.useRef(null);
5109
- const triggerRef = React90__default.useRef(null);
5107
+ const [isVisible, setIsVisible] = React88__default.useState(false);
5108
+ const timeoutRef = React88__default.useRef(null);
5109
+ const triggerRef = React88__default.useRef(null);
5110
5110
  const handleMouseEnter = () => {
5111
5111
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5112
5112
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -5117,7 +5117,7 @@ var init_LawReferenceTooltip = __esm({
5117
5117
  };
5118
5118
  const { revealed, triggerProps } = useTapReveal({ refs: [triggerRef] });
5119
5119
  const open = isVisible || revealed;
5120
- React90__default.useEffect(() => {
5120
+ React88__default.useEffect(() => {
5121
5121
  return () => {
5122
5122
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5123
5123
  };
@@ -5329,7 +5329,7 @@ var init_StatusDot = __esm({
5329
5329
  md: "w-2.5 h-2.5",
5330
5330
  lg: "w-3 h-3"
5331
5331
  };
5332
- StatusDot = React90__default.forwardRef(
5332
+ StatusDot = React88__default.forwardRef(
5333
5333
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
5334
5334
  return /* @__PURE__ */ jsx(
5335
5335
  "span",
@@ -5383,7 +5383,7 @@ var init_TrendIndicator = __esm({
5383
5383
  down: "trending-down",
5384
5384
  flat: "arrow-right"
5385
5385
  };
5386
- TrendIndicator = React90__default.forwardRef(
5386
+ TrendIndicator = React88__default.forwardRef(
5387
5387
  ({
5388
5388
  className,
5389
5389
  value,
@@ -5450,7 +5450,7 @@ var init_RangeSlider = __esm({
5450
5450
  md: "w-4 h-4",
5451
5451
  lg: "w-5 h-5"
5452
5452
  };
5453
- RangeSlider = React90__default.forwardRef(
5453
+ RangeSlider = React88__default.forwardRef(
5454
5454
  ({
5455
5455
  className,
5456
5456
  min = 0,
@@ -5958,7 +5958,7 @@ var init_ContentSection = __esm({
5958
5958
  md: "py-16",
5959
5959
  lg: "py-24"
5960
5960
  };
5961
- ContentSection = React90__default.forwardRef(
5961
+ ContentSection = React88__default.forwardRef(
5962
5962
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
5963
5963
  return /* @__PURE__ */ jsx(
5964
5964
  Box,
@@ -6492,7 +6492,7 @@ var init_AnimatedReveal = __esm({
6492
6492
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6493
6493
  "none": {}
6494
6494
  };
6495
- AnimatedReveal = React90__default.forwardRef(
6495
+ AnimatedReveal = React88__default.forwardRef(
6496
6496
  ({
6497
6497
  trigger = "scroll",
6498
6498
  animation = "fade-up",
@@ -6652,7 +6652,7 @@ var init_AnimatedGraphic = __esm({
6652
6652
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
6653
6653
  "use client";
6654
6654
  init_cn();
6655
- AnimatedGraphic = React90__default.forwardRef(
6655
+ AnimatedGraphic = React88__default.forwardRef(
6656
6656
  ({
6657
6657
  src,
6658
6658
  svgContent,
@@ -6675,7 +6675,7 @@ var init_AnimatedGraphic = __esm({
6675
6675
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6676
6676
  const resolvedSvg = svgContent ?? fetchedSvg;
6677
6677
  const prevAnimateRef = useRef(animate);
6678
- const setRef = React90__default.useCallback(
6678
+ const setRef = React88__default.useCallback(
6679
6679
  (node) => {
6680
6680
  containerRef.current = node;
6681
6681
  if (typeof ref === "function") ref(node);
@@ -6897,50 +6897,23 @@ function ScoreDisplay({
6897
6897
  icon,
6898
6898
  size = "md",
6899
6899
  className,
6900
- animated = true,
6901
6900
  locale = "en-US"
6902
6901
  }) {
6903
6902
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof score === "number" && !Number.isNaN(score) ? score : 0;
6904
- const [displayValue, setDisplayValue] = React90.useState(resolvedValue);
6905
- const [isAnimating, setIsAnimating] = React90.useState(false);
6906
- React90.useEffect(() => {
6907
- if (!animated || displayValue === resolvedValue) {
6908
- setDisplayValue(resolvedValue);
6909
- return;
6910
- }
6911
- setIsAnimating(true);
6912
- const diff = resolvedValue - displayValue;
6913
- const steps = Math.min(Math.abs(diff), 20);
6914
- const increment = diff / steps;
6915
- let current = displayValue;
6916
- let step = 0;
6917
- const timer = setInterval(() => {
6918
- step++;
6919
- current += increment;
6920
- setDisplayValue(Math.round(current));
6921
- if (step >= steps) {
6922
- clearInterval(timer);
6923
- setDisplayValue(resolvedValue);
6924
- setIsAnimating(false);
6925
- }
6926
- }, 50);
6927
- return () => clearInterval(timer);
6928
- }, [resolvedValue, animated]);
6929
- const formattedValue = new Intl.NumberFormat(locale).format(displayValue);
6903
+ const formattedValue = new Intl.NumberFormat(locale).format(resolvedValue);
6930
6904
  return /* @__PURE__ */ jsxs(
6931
6905
  "div",
6932
6906
  {
6933
6907
  className: cn(
6934
6908
  "flex items-center gap-2 font-bold",
6935
6909
  sizeMap2[size],
6936
- isAnimating && "animate-pulse",
6937
6910
  className
6938
6911
  ),
6939
6912
  children: [
6940
6913
  assetUrl ? /* @__PURE__ */ jsx(
6941
6914
  "img",
6942
6915
  {
6943
- src: assetUrl,
6916
+ src: assetUrl.url,
6944
6917
  alt: "",
6945
6918
  width: 20,
6946
6919
  height: 20,
@@ -6957,7 +6930,6 @@ function ScoreDisplay({
6957
6930
  var sizeMap2, DEFAULT_ASSET_URL;
6958
6931
  var init_ScoreDisplay = __esm({
6959
6932
  "components/game/atoms/ScoreDisplay.tsx"() {
6960
- "use client";
6961
6933
  init_cn();
6962
6934
  init_Icon();
6963
6935
  sizeMap2 = {
@@ -6966,7 +6938,11 @@ var init_ScoreDisplay = __esm({
6966
6938
  lg: "text-2xl",
6967
6939
  xl: "text-4xl"
6968
6940
  };
6969
- DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
6941
+ DEFAULT_ASSET_URL = {
6942
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
6943
+ role: "effect",
6944
+ category: "effect"
6945
+ };
6970
6946
  ScoreDisplay.displayName = "ScoreDisplay";
6971
6947
  }
6972
6948
  });
@@ -6986,9 +6962,9 @@ function ControlButton({
6986
6962
  className
6987
6963
  }) {
6988
6964
  const eventBus = useEventBus();
6989
- const [isPressed, setIsPressed] = React90.useState(false);
6965
+ const [isPressed, setIsPressed] = React88.useState(false);
6990
6966
  const actualPressed = pressed ?? isPressed;
6991
- const handlePointerDown = React90.useCallback(
6967
+ const handlePointerDown = React88.useCallback(
6992
6968
  (e) => {
6993
6969
  e.preventDefault();
6994
6970
  if (disabled) return;
@@ -6998,7 +6974,7 @@ function ControlButton({
6998
6974
  },
6999
6975
  [disabled, pressEvent, eventBus, onPress]
7000
6976
  );
7001
- const handlePointerUp = React90.useCallback(
6977
+ const handlePointerUp = React88.useCallback(
7002
6978
  (e) => {
7003
6979
  e.preventDefault();
7004
6980
  if (disabled) return;
@@ -7008,7 +6984,7 @@ function ControlButton({
7008
6984
  },
7009
6985
  [disabled, releaseEvent, eventBus, onRelease]
7010
6986
  );
7011
- const handlePointerLeave = React90.useCallback(
6987
+ const handlePointerLeave = React88.useCallback(
7012
6988
  (e) => {
7013
6989
  if (isPressed) {
7014
6990
  setIsPressed(false);
@@ -7042,7 +7018,7 @@ function ControlButton({
7042
7018
  children: assetUrl ? /* @__PURE__ */ jsx(
7043
7019
  "img",
7044
7020
  {
7045
- src: assetUrl,
7021
+ src: assetUrl.url,
7046
7022
  alt: "",
7047
7023
  width: 24,
7048
7024
  height: 24,
@@ -7082,7 +7058,11 @@ var init_ControlButton = __esm({
7082
7058
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
7083
7059
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
7084
7060
  };
7085
- DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
7061
+ DEFAULT_ASSET_URL2 = {
7062
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
7063
+ role: "effect",
7064
+ category: "effect"
7065
+ };
7086
7066
  ControlButton.displayName = "ControlButton";
7087
7067
  }
7088
7068
  });
@@ -7096,13 +7076,6 @@ var init_spriteSheetConstants = __esm({
7096
7076
  });
7097
7077
 
7098
7078
  // components/game/organisms/utils/spriteAnimation.ts
7099
- function inferDirection(dx, dy) {
7100
- if (dx === 0 && dy === 0) return "se";
7101
- if (dx >= 0 && dy >= 0) return "se";
7102
- if (dx <= 0 && dy >= 0) return "sw";
7103
- if (dx >= 0 && dy <= 0) return "ne";
7104
- return "nw";
7105
- }
7106
7079
  function resolveSheetDirection(facing) {
7107
7080
  switch (facing) {
7108
7081
  case "se":
@@ -7123,25 +7096,12 @@ function frameRect(frame, row, columns, frameWidth, frameHeight) {
7123
7096
  sh: frameHeight
7124
7097
  };
7125
7098
  }
7126
- function getCurrentFrameFromDef(def, elapsed) {
7127
- const frameDuration = 1e3 / def.frameRate;
7128
- const totalDuration = def.frames * frameDuration;
7129
- if (def.loop) {
7130
- const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
7131
- return { frame: frame2, finished: false };
7132
- }
7133
- if (elapsed >= totalDuration) {
7134
- return { frame: def.frames - 1, finished: true };
7135
- }
7136
- const frame = Math.floor(elapsed / frameDuration);
7137
- return { frame, finished: false };
7138
- }
7139
7099
  var init_spriteAnimation = __esm({
7140
7100
  "components/game/organisms/utils/spriteAnimation.ts"() {
7141
7101
  }
7142
7102
  });
7143
7103
  function Sprite({
7144
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7104
+ spritesheet = DEFAULT_SPRITESHEET,
7145
7105
  frameWidth = 64,
7146
7106
  frameHeight = 64,
7147
7107
  frame = 0,
@@ -7154,6 +7114,8 @@ function Sprite({
7154
7114
  opacity = 1,
7155
7115
  zIndex = 0,
7156
7116
  columns = 16,
7117
+ animState: _animState,
7118
+ frameRate: _frameRate,
7157
7119
  className,
7158
7120
  onClick,
7159
7121
  action
@@ -7192,7 +7154,7 @@ function Sprite({
7192
7154
  position: "absolute",
7193
7155
  width: frameWidth,
7194
7156
  height: frameHeight,
7195
- backgroundImage: `url(${spritesheet})`,
7157
+ backgroundImage: `url(${spritesheet.url})`,
7196
7158
  backgroundPosition,
7197
7159
  backgroundRepeat: "no-repeat",
7198
7160
  imageRendering: "pixelated",
@@ -7205,11 +7167,17 @@ function Sprite({
7205
7167
  }
7206
7168
  );
7207
7169
  }
7170
+ var DEFAULT_SPRITESHEET;
7208
7171
  var init_Sprite = __esm({
7209
7172
  "components/game/atoms/Sprite.tsx"() {
7210
7173
  "use client";
7211
7174
  init_useEventBus();
7212
7175
  init_spriteAnimation();
7176
+ DEFAULT_SPRITESHEET = {
7177
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7178
+ role: "tile",
7179
+ category: "tile"
7180
+ };
7213
7181
  }
7214
7182
  });
7215
7183
  function StateIndicator({
@@ -7239,7 +7207,7 @@ function StateIndicator({
7239
7207
  /* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsx(
7240
7208
  "img",
7241
7209
  {
7242
- src: assetUrl,
7210
+ src: assetUrl.url,
7243
7211
  alt: displayLabel,
7244
7212
  width: 16,
7245
7213
  height: 16,
@@ -7258,7 +7226,11 @@ var init_StateIndicator = __esm({
7258
7226
  init_Box();
7259
7227
  init_Icon();
7260
7228
  init_cn();
7261
- DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
7229
+ DEFAULT_ASSET_URL3 = {
7230
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
7231
+ role: "effect",
7232
+ category: "item"
7233
+ };
7262
7234
  DEFAULT_STATE_STYLES = {
7263
7235
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
7264
7236
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -7356,7 +7328,7 @@ function ResourceCounter({
7356
7328
  assetUrl ? /* @__PURE__ */ jsx(
7357
7329
  "img",
7358
7330
  {
7359
- src: assetUrl,
7331
+ src: assetUrl.url,
7360
7332
  alt: label,
7361
7333
  width: sizes.img,
7362
7334
  height: sizes.img,
@@ -7389,7 +7361,11 @@ var init_ResourceCounter = __esm({
7389
7361
  error: "text-error",
7390
7362
  muted: "text-muted-foreground"
7391
7363
  };
7392
- DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
7364
+ DEFAULT_ASSET_URL4 = {
7365
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
7366
+ role: "effect",
7367
+ category: "world"
7368
+ };
7393
7369
  sizeMap5 = {
7394
7370
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
7395
7371
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -7435,7 +7411,7 @@ function ItemSlot({
7435
7411
  assetUrl ? /* @__PURE__ */ jsx(
7436
7412
  "img",
7437
7413
  {
7438
- src: assetUrl,
7414
+ src: assetUrl?.url,
7439
7415
  alt: label,
7440
7416
  width: px,
7441
7417
  height: px,
@@ -7483,7 +7459,11 @@ var init_ItemSlot = __esm({
7483
7459
  epic: "shadow-lg",
7484
7460
  legendary: "shadow-lg"
7485
7461
  };
7486
- DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
7462
+ DEFAULT_ASSET_URL5 = {
7463
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
7464
+ role: "effect",
7465
+ category: "item"
7466
+ };
7487
7467
  assetSizeMap = {
7488
7468
  sm: 28,
7489
7469
  md: 40,
@@ -7529,7 +7509,7 @@ function TurnIndicator({
7529
7509
  assetUrl ? /* @__PURE__ */ jsx(
7530
7510
  "img",
7531
7511
  {
7532
- src: assetUrl,
7512
+ src: assetUrl.url,
7533
7513
  alt: "",
7534
7514
  width: 12,
7535
7515
  height: 12,
@@ -7552,7 +7532,11 @@ var init_TurnIndicator = __esm({
7552
7532
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
7553
7533
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
7554
7534
  };
7555
- DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
7535
+ DEFAULT_ASSET_URL6 = {
7536
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
7537
+ role: "effect",
7538
+ category: "effect"
7539
+ };
7556
7540
  TurnIndicator.displayName = "TurnIndicator";
7557
7541
  }
7558
7542
  });
@@ -7591,7 +7575,7 @@ function ComboCounter({
7591
7575
  assetUrl && /* @__PURE__ */ jsx(
7592
7576
  "img",
7593
7577
  {
7594
- src: assetUrl,
7578
+ src: assetUrl.url,
7595
7579
  alt: "combo",
7596
7580
  width: 24,
7597
7581
  height: 24,
@@ -7617,7 +7601,11 @@ var DEFAULT_ASSET_URL7, sizeMap8;
7617
7601
  var init_ComboCounter = __esm({
7618
7602
  "components/game/atoms/ComboCounter.tsx"() {
7619
7603
  init_cn();
7620
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
7604
+ DEFAULT_ASSET_URL7 = {
7605
+ url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
7606
+ role: "effect",
7607
+ category: "effect"
7608
+ };
7621
7609
  sizeMap8 = {
7622
7610
  sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
7623
7611
  md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
@@ -7637,21 +7625,6 @@ function XPBar({
7637
7625
  }) {
7638
7626
  const sizes = sizeMap9[size];
7639
7627
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
7640
- const [fillWidth, setFillWidth] = React90.useState(animated ? 0 : percentage);
7641
- React90.useEffect(() => {
7642
- if (!animated) {
7643
- setFillWidth(percentage);
7644
- return;
7645
- }
7646
- let frame2;
7647
- const frame1 = requestAnimationFrame(() => {
7648
- frame2 = requestAnimationFrame(() => setFillWidth(percentage));
7649
- });
7650
- return () => {
7651
- cancelAnimationFrame(frame1);
7652
- cancelAnimationFrame(frame2);
7653
- };
7654
- }, [animated, percentage]);
7655
7628
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), children: [
7656
7629
  level != null && /* @__PURE__ */ jsxs(
7657
7630
  "span",
@@ -7683,7 +7656,7 @@ function XPBar({
7683
7656
  "bg-gradient-to-r from-accent to-info",
7684
7657
  animated && "transition-all duration-500 ease-out"
7685
7658
  ),
7686
- style: { width: `${fillWidth}%` }
7659
+ style: { width: `${percentage}%` }
7687
7660
  }
7688
7661
  )
7689
7662
  }
@@ -7700,7 +7673,6 @@ function XPBar({
7700
7673
  var sizeMap9;
7701
7674
  var init_XPBar = __esm({
7702
7675
  "components/game/atoms/XPBar.tsx"() {
7703
- "use client";
7704
7676
  init_cn();
7705
7677
  sizeMap9 = {
7706
7678
  sm: { bar: "h-2", text: "text-xs", badge: "text-xs px-1.5 py-0.5" },
@@ -7753,7 +7725,7 @@ function WaypointMarker({
7753
7725
  children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(
7754
7726
  "img",
7755
7727
  {
7756
- src: assetUrl,
7728
+ src: assetUrl.url,
7757
7729
  alt: label,
7758
7730
  width: sizes.img,
7759
7731
  height: sizes.img,
@@ -7782,7 +7754,11 @@ var init_WaypointMarker = __esm({
7782
7754
  "components/game/atoms/WaypointMarker.tsx"() {
7783
7755
  init_cn();
7784
7756
  init_Icon();
7785
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
7757
+ DEFAULT_ASSET_URL8 = {
7758
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
7759
+ role: "effect",
7760
+ category: "world"
7761
+ };
7786
7762
  sizeMap10 = {
7787
7763
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
7788
7764
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -7823,7 +7799,7 @@ function StatusEffect({
7823
7799
  /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(
7824
7800
  "img",
7825
7801
  {
7826
- src: assetUrl,
7802
+ src: assetUrl.url,
7827
7803
  alt: label,
7828
7804
  width: sizes.img,
7829
7805
  height: sizes.img,
@@ -7862,7 +7838,11 @@ var init_StatusEffect = __esm({
7862
7838
  "components/game/atoms/StatusEffect.tsx"() {
7863
7839
  init_cn();
7864
7840
  init_Icon();
7865
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
7841
+ DEFAULT_ASSET_URL9 = {
7842
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
7843
+ role: "effect",
7844
+ category: "effect"
7845
+ };
7866
7846
  sizeMap11 = {
7867
7847
  sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]", img: 20 },
7868
7848
  md: { container: "w-10 h-10", icon: "text-base", badge: "text-xs -top-1 -right-1 w-5 h-5", timer: "text-xs", img: 28 },
@@ -7900,7 +7880,7 @@ function DamageNumber({
7900
7880
  assetUrl && /* @__PURE__ */ jsx(
7901
7881
  "img",
7902
7882
  {
7903
- src: assetUrl,
7883
+ src: assetUrl.url,
7904
7884
  alt: "",
7905
7885
  width: 14,
7906
7886
  height: 14,
@@ -7936,14 +7916,18 @@ var init_DamageNumber = __esm({
7936
7916
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
7937
7917
  }
7938
7918
  `;
7939
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
7919
+ DEFAULT_ASSET_URL10 = {
7920
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
7921
+ role: "effect",
7922
+ category: "effect"
7923
+ };
7940
7924
  DamageNumber.displayName = "DamageNumber";
7941
7925
  }
7942
7926
  });
7943
7927
  function DialogueBubble({
7944
7928
  speaker = "Hero",
7945
7929
  text = "The dungeon awaits. Choose your path wisely.",
7946
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
7930
+ portrait = DEFAULT_PORTRAIT,
7947
7931
  position = "bottom",
7948
7932
  className
7949
7933
  }) {
@@ -7959,7 +7943,7 @@ function DialogueBubble({
7959
7943
  portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(
7960
7944
  "img",
7961
7945
  {
7962
- src: portrait,
7946
+ src: portrait?.url,
7963
7947
  alt: speaker ?? "speaker",
7964
7948
  className: "w-full h-full object-cover"
7965
7949
  }
@@ -7972,9 +7956,15 @@ function DialogueBubble({
7972
7956
  }
7973
7957
  );
7974
7958
  }
7959
+ var DEFAULT_PORTRAIT;
7975
7960
  var init_DialogueBubble = __esm({
7976
7961
  "components/game/atoms/DialogueBubble.tsx"() {
7977
7962
  init_cn();
7963
+ DEFAULT_PORTRAIT = {
7964
+ url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
7965
+ role: "effect",
7966
+ category: "character"
7967
+ };
7978
7968
  DialogueBubble.displayName = "DialogueBubble";
7979
7969
  }
7980
7970
  });
@@ -8018,7 +8008,7 @@ function ChoiceButton({
8018
8008
  assetUrl ? /* @__PURE__ */ jsx(
8019
8009
  "img",
8020
8010
  {
8021
- src: assetUrl,
8011
+ src: assetUrl.url,
8022
8012
  alt: "",
8023
8013
  width: 16,
8024
8014
  height: 16,
@@ -8088,7 +8078,7 @@ function ActionButton({
8088
8078
  assetUrl ? /* @__PURE__ */ jsx(
8089
8079
  "img",
8090
8080
  {
8091
- src: assetUrl,
8081
+ src: assetUrl.url,
8092
8082
  alt: "",
8093
8083
  width: 16,
8094
8084
  height: 16,
@@ -8132,7 +8122,11 @@ var init_ActionButton = __esm({
8132
8122
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
8133
8123
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
8134
8124
  };
8135
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
8125
+ DEFAULT_ASSET_URL11 = {
8126
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
8127
+ role: "effect",
8128
+ category: "effect"
8129
+ };
8136
8130
  ActionButton.displayName = "ActionButton";
8137
8131
  }
8138
8132
  });
@@ -8146,9 +8140,9 @@ function MiniMap({
8146
8140
  viewportRect = DEFAULT_VIEWPORT,
8147
8141
  className
8148
8142
  }) {
8149
- const canvasRef = React90.useRef(null);
8150
- const frameRef = React90.useRef(0);
8151
- React90.useEffect(() => {
8143
+ const canvasRef = React88.useRef(null);
8144
+ const frameRef = React88.useRef(0);
8145
+ React88.useEffect(() => {
8152
8146
  const canvas = canvasRef.current;
8153
8147
  if (!canvas) return;
8154
8148
  const ctx = canvas.getContext("2d");
@@ -8337,7 +8331,7 @@ var init_ErrorBoundary = __esm({
8337
8331
  }
8338
8332
  );
8339
8333
  };
8340
- ErrorBoundary = class extends React90__default.Component {
8334
+ ErrorBoundary = class extends React88__default.Component {
8341
8335
  constructor(props) {
8342
8336
  super(props);
8343
8337
  __publicField(this, "reset", () => {
@@ -9004,7 +8998,7 @@ var init_Container = __esm({
9004
8998
  as: Component2 = "div"
9005
8999
  }) => {
9006
9000
  const resolvedSize = maxWidth ?? size ?? "lg";
9007
- return React90__default.createElement(
9001
+ return React88__default.createElement(
9008
9002
  Component2,
9009
9003
  {
9010
9004
  className: cn(
@@ -9727,8 +9721,8 @@ function ActionButtons({
9727
9721
  disabled
9728
9722
  }) {
9729
9723
  const eventBus = useEventBus();
9730
- const [activeButtons, setActiveButtons] = React90.useState(/* @__PURE__ */ new Set());
9731
- const handlePress = React90.useCallback(
9724
+ const [activeButtons, setActiveButtons] = React88.useState(/* @__PURE__ */ new Set());
9725
+ const handlePress = React88.useCallback(
9732
9726
  (id) => {
9733
9727
  setActiveButtons((prev) => new Set(prev).add(id));
9734
9728
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -9736,7 +9730,7 @@ function ActionButtons({
9736
9730
  },
9737
9731
  [actionEvent, eventBus, onAction]
9738
9732
  );
9739
- const handleRelease = React90.useCallback(
9733
+ const handleRelease = React88.useCallback(
9740
9734
  (id) => {
9741
9735
  setActiveButtons((prev) => {
9742
9736
  const next = new Set(prev);
@@ -10566,50 +10560,6 @@ var init_AuthLayout = __esm({
10566
10560
  AuthLayout.displayName = "AuthLayout";
10567
10561
  }
10568
10562
  });
10569
- var LoadingState;
10570
- var init_LoadingState = __esm({
10571
- "components/core/molecules/LoadingState.tsx"() {
10572
- "use client";
10573
- init_cn();
10574
- init_atoms2();
10575
- init_Stack();
10576
- init_Typography();
10577
- LoadingState = ({
10578
- title,
10579
- message,
10580
- className
10581
- }) => {
10582
- const { t } = useTranslate();
10583
- const displayMessage = message ?? t("common.loading");
10584
- return /* @__PURE__ */ jsxs(
10585
- VStack,
10586
- {
10587
- align: "center",
10588
- className: cn(
10589
- "justify-center py-12",
10590
- className
10591
- ),
10592
- children: [
10593
- /* @__PURE__ */ jsx(Spinner, { size: "lg" }),
10594
- title && /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "mt-4 text-lg font-semibold text-foreground", children: title }),
10595
- /* @__PURE__ */ jsx(
10596
- Typography,
10597
- {
10598
- variant: "small",
10599
- className: cn(
10600
- "text-muted-foreground",
10601
- title ? "mt-2" : "mt-4"
10602
- ),
10603
- children: displayMessage
10604
- }
10605
- )
10606
- ]
10607
- }
10608
- );
10609
- };
10610
- LoadingState.displayName = "LoadingState";
10611
- }
10612
- });
10613
10563
  function getState() {
10614
10564
  if (typeof window !== "undefined") {
10615
10565
  const w = window;
@@ -11107,12 +11057,7 @@ var init_useCanvasGestures = __esm({
11107
11057
  }
11108
11058
  });
11109
11059
  function unitAtlasUrl(unit) {
11110
- if (unit.spriteSheet) return unit.spriteSheet;
11111
- const sprite = unit.sprite;
11112
- if (!sprite) return null;
11113
- const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
11114
- if (!match) return null;
11115
- return `${match[1]}.json`;
11060
+ return unit.spriteSheet?.url ?? null;
11116
11061
  }
11117
11062
  function resolveSheetUrl(atlasUrl, relativeSheetPath) {
11118
11063
  try {
@@ -11127,9 +11072,6 @@ function useUnitSpriteAtlas(units) {
11127
11072
  const loadingRef = useRef(/* @__PURE__ */ new Set());
11128
11073
  const [pendingCount, setPendingCount] = useState(0);
11129
11074
  const [, forceTick] = useState(0);
11130
- const animStatesRef = useRef(/* @__PURE__ */ new Map());
11131
- const lastTickRef = useRef(0);
11132
- const rafRef = useRef(0);
11133
11075
  const atlasUrls = useMemo(() => {
11134
11076
  const set = /* @__PURE__ */ new Set();
11135
11077
  for (const unit of units) {
@@ -11175,54 +11117,6 @@ function useUnitSpriteAtlas(units) {
11175
11117
  }
11176
11118
  return [...urls];
11177
11119
  }, [units, pendingCount]);
11178
- useEffect(() => {
11179
- const hasAtlasUnits = units.some((u) => unitAtlasUrl(u) !== null);
11180
- if (!hasAtlasUnits) return;
11181
- let running = true;
11182
- const tick = (ts) => {
11183
- if (!running) return;
11184
- const last = lastTickRef.current || ts;
11185
- const delta = ts - last;
11186
- lastTickRef.current = ts;
11187
- const states = animStatesRef.current;
11188
- const currentIds = /* @__PURE__ */ new Set();
11189
- for (const unit of units) {
11190
- if (unitAtlasUrl(unit) === null) continue;
11191
- currentIds.add(unit.id);
11192
- let state = states.get(unit.id);
11193
- if (!state) {
11194
- state = { animation: "idle", direction: "se", elapsed: 0, walkHold: 0, prev: null };
11195
- states.set(unit.id, state);
11196
- }
11197
- const posX = unit.position?.x ?? unit.x ?? 0;
11198
- const posY = unit.position?.y ?? unit.y ?? 0;
11199
- if (state.prev) {
11200
- const dx = posX - state.prev.x;
11201
- const dy = posY - state.prev.y;
11202
- if (dx !== 0 || dy !== 0) {
11203
- state.animation = "walk";
11204
- state.direction = inferDirection(dx, dy);
11205
- state.walkHold = WALK_HOLD_MS;
11206
- } else if (state.animation === "walk") {
11207
- state.walkHold -= delta;
11208
- if (state.walkHold <= 0) state.animation = "idle";
11209
- }
11210
- }
11211
- state.prev = { x: posX, y: posY };
11212
- state.elapsed += delta;
11213
- }
11214
- for (const id of states.keys()) {
11215
- if (!currentIds.has(id)) states.delete(id);
11216
- }
11217
- rafRef.current = requestAnimationFrame(tick);
11218
- };
11219
- rafRef.current = requestAnimationFrame(tick);
11220
- return () => {
11221
- running = false;
11222
- cancelAnimationFrame(rafRef.current);
11223
- lastTickRef.current = 0;
11224
- };
11225
- }, [units]);
11226
11120
  const resolveUnitFrame = useCallback((unitId) => {
11227
11121
  const unit = units.find((u) => u.id === unitId);
11228
11122
  if (!unit) return null;
@@ -11230,18 +11124,14 @@ function useUnitSpriteAtlas(units) {
11230
11124
  if (!atlasUrl) return null;
11231
11125
  const atlas = atlasCacheRef.current.get(atlasUrl);
11232
11126
  if (!atlas) return null;
11233
- const state = animStatesRef.current.get(unitId);
11234
- const animation = state?.animation ?? "idle";
11235
- const direction = state?.direction ?? "se";
11236
- const elapsed = state?.elapsed ?? 0;
11127
+ const animation = unit.animation ?? "idle";
11128
+ const frame = unit.frame ?? 0;
11237
11129
  const def = atlas.animations[animation] ?? atlas.animations.idle;
11238
11130
  if (!def) return null;
11239
- const { sheetDir, flipX } = resolveSheetDirection(direction);
11131
+ const { sheetDir, flipX } = resolveSheetDirection("se");
11240
11132
  const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
11241
11133
  if (!rel) return null;
11242
11134
  const sheetUrl = resolveSheetUrl(atlasUrl, rel);
11243
- const isIdle = animation === "idle";
11244
- const frame = isIdle ? 0 : getCurrentFrameFromDef(def, elapsed).frame;
11245
11135
  const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
11246
11136
  return {
11247
11137
  sheetUrl,
@@ -11250,17 +11140,15 @@ function useUnitSpriteAtlas(units) {
11250
11140
  sw: rect.sw,
11251
11141
  sh: rect.sh,
11252
11142
  flipX,
11253
- applyBreathing: isIdle
11143
+ applyBreathing: animation === "idle"
11254
11144
  };
11255
11145
  }, [units]);
11256
11146
  return { sheetUrls, resolveUnitFrame, pendingCount };
11257
11147
  }
11258
- var WALK_HOLD_MS;
11259
11148
  var init_useUnitSpriteAtlas = __esm({
11260
11149
  "components/game/molecules/useUnitSpriteAtlas.ts"() {
11261
11150
  "use client";
11262
11151
  init_spriteAnimation();
11263
- WALK_HOLD_MS = 600;
11264
11152
  }
11265
11153
  });
11266
11154
 
@@ -11328,6 +11216,7 @@ function IsometricCanvas({
11328
11216
  tiles: _tilesPropRaw = [],
11329
11217
  units: _unitsPropRaw = [],
11330
11218
  features: _featuresPropRaw = [],
11219
+ effects: _effectsPropRaw = [],
11331
11220
  // Interaction state
11332
11221
  selectedUnitId = null,
11333
11222
  validMoves = [],
@@ -11360,23 +11249,21 @@ function IsometricCanvas({
11360
11249
  resolveUnitFrame,
11361
11250
  effectSpriteUrls = [],
11362
11251
  onDrawEffects,
11363
- hasActiveEffects: hasActiveEffects2 = false,
11252
+ hasActiveEffects: _hasActiveEffects = false,
11364
11253
  // Tuning
11365
11254
  diamondTopY: diamondTopYProp,
11366
11255
  // Remote asset loading
11367
- assetBaseUrl,
11368
11256
  assetManifest
11369
11257
  }) {
11370
11258
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
11371
11259
  const unitsProp = Array.isArray(_unitsPropRaw) ? _unitsPropRaw : [];
11372
11260
  const featuresProp = Array.isArray(_featuresPropRaw) ? _featuresPropRaw : [];
11261
+ const effects = Array.isArray(_effectsPropRaw) ? _effectsPropRaw : [];
11373
11262
  const eventBus = useEventBus();
11374
11263
  const { t } = useTranslate();
11375
11264
  const canvasRef = useRef(null);
11376
11265
  const containerRef = useRef(null);
11377
- const minimapRef = useRef(null);
11378
- const animTimeRef = useRef(0);
11379
- const rafIdRef = useRef(0);
11266
+ const lerpRafRef = useRef(0);
11380
11267
  const [viewportSize, setViewportSize] = useState({ width: 800, height: 600 });
11381
11268
  useEffect(() => {
11382
11269
  const el = containerRef.current;
@@ -11400,7 +11287,7 @@ function IsometricCanvas({
11400
11287
  () => unitsProp.map((u) => u.position ? u : { ...u, position: { x: u.x ?? 0, y: u.y ?? 0 } }),
11401
11288
  [unitsProp]
11402
11289
  );
11403
- const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal, pendingCount: atlasPending } = useUnitSpriteAtlas(units);
11290
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal } = useUnitSpriteAtlas(units);
11404
11291
  const resolveFrameForUnit = useCallback((unitId) => {
11405
11292
  return resolveUnitFrame?.(unitId) ?? resolveUnitFrameInternal(unitId);
11406
11293
  }, [resolveUnitFrame, resolveUnitFrameInternal]);
@@ -11447,55 +11334,49 @@ function IsometricCanvas({
11447
11334
  const attackTargetSet = useMemo(() => {
11448
11335
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
11449
11336
  }, [attackTargets]);
11450
- const resolveManifestUrl7 = useCallback((relativePath) => {
11451
- if (!relativePath) return void 0;
11452
- if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
11453
- return relativePath;
11454
- }, [assetBaseUrl]);
11455
11337
  const spriteUrls = useMemo(() => {
11456
11338
  const urls = [];
11457
11339
  for (const tile of sortedTiles) {
11458
- if (tile.terrainSprite) urls.push(tile.terrainSprite);
11340
+ if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
11459
11341
  else if (getTerrainSprite) {
11460
11342
  const url = getTerrainSprite(tile.terrain ?? "");
11461
11343
  if (url) urls.push(url);
11462
11344
  } else {
11463
- const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
11345
+ const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
11464
11346
  if (url) urls.push(url);
11465
11347
  }
11466
11348
  }
11467
11349
  for (const feature of features) {
11468
- if (feature.sprite) urls.push(feature.sprite);
11350
+ if (feature.sprite) urls.push(feature.sprite.url);
11469
11351
  else if (getFeatureSprite) {
11470
11352
  const url = getFeatureSprite(feature.type);
11471
11353
  if (url) urls.push(url);
11472
11354
  } else {
11473
- const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
11355
+ const url = assetManifest?.features?.[feature.type]?.url;
11474
11356
  if (url) urls.push(url);
11475
11357
  }
11476
11358
  }
11477
11359
  for (const unit of units) {
11478
- if (unit.sprite) urls.push(unit.sprite);
11360
+ if (unit.sprite) urls.push(unit.sprite.url);
11479
11361
  else if (getUnitSprite) {
11480
11362
  const url = getUnitSprite(unit);
11481
11363
  if (url) urls.push(url);
11482
11364
  } else if (unit.unitType) {
11483
- const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
11365
+ const url = assetManifest?.units?.[unit.unitType]?.url;
11484
11366
  if (url) urls.push(url);
11485
11367
  }
11486
11368
  }
11487
11369
  if (assetManifest?.effects) {
11488
- for (const path of Object.values(assetManifest.effects)) {
11489
- const url = resolveManifestUrl7(path);
11490
- if (url) urls.push(url);
11370
+ for (const asset of Object.values(assetManifest.effects)) {
11371
+ if (asset.url) urls.push(asset.url);
11491
11372
  }
11492
11373
  }
11493
11374
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
11494
11375
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
11495
11376
  if (backgroundImage) urls.push(backgroundImage);
11496
11377
  return [...new Set(urls.filter(Boolean))];
11497
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
11498
- const { getImage, pendingCount } = useImageCache(spriteUrls);
11378
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest]);
11379
+ const { getImage, pendingCount: _imagePendingCount } = useImageCache(spriteUrls);
11499
11380
  useEffect(() => {
11500
11381
  if (typeof window === "undefined") return;
11501
11382
  const canvas = canvasRef.current;
@@ -11519,71 +11400,34 @@ function IsometricCanvas({
11519
11400
  lerpToTarget
11520
11401
  } = useCamera();
11521
11402
  const resolveTerrainSpriteUrl = useCallback((tile) => {
11522
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
11523
- }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
11403
+ return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
11404
+ }, [getTerrainSprite, assetManifest]);
11524
11405
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
11525
- return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
11526
- }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
11406
+ return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
11407
+ }, [getFeatureSprite, assetManifest]);
11527
11408
  const resolveUnitSpriteUrl = useCallback((unit) => {
11528
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
11529
- }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
11530
- const drawMinimap = useCallback(() => {
11531
- if (!showMinimap) return;
11532
- const miniCanvas = minimapRef.current;
11533
- if (!miniCanvas || sortedTiles.length === 0) return;
11534
- const mCtx = miniCanvas.getContext("2d");
11535
- if (!mCtx) return;
11536
- const mW = 150;
11537
- const mH = 100;
11538
- miniCanvas.width = mW;
11539
- miniCanvas.height = mH;
11540
- mCtx.clearRect(0, 0, mW, mH);
11541
- const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
11542
- const minX = Math.min(...allScreenPos.map((p2) => p2.x));
11543
- const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
11544
- const minY = Math.min(...allScreenPos.map((p2) => p2.y));
11545
- const tileBottomExtent = tileLayout === "hex" || tileLayout === "flat" ? scaledTileWidth : scaledTileHeight;
11546
- const maxY = Math.max(...allScreenPos.map((p2) => p2.y + tileBottomExtent));
11547
- const worldW = maxX - minX;
11548
- const worldH = maxY - minY;
11549
- const scaleM = Math.min(mW / worldW, mH / worldH) * 0.9;
11550
- const offsetMx = (mW - worldW * scaleM) / 2;
11551
- const offsetMy = (mH - worldH * scaleM) / 2;
11552
- for (const tile of sortedTiles) {
11553
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
11554
- const mx = (pos.x - minX) * scaleM + offsetMx;
11555
- const my = (pos.y - minY) * scaleM + offsetMy;
11556
- const mTileW = scaledTileWidth * scaleM;
11557
- const mFloorH = scaledFloorHeight * scaleM;
11558
- mCtx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : "#4ade80";
11559
- mCtx.beginPath();
11560
- mCtx.moveTo(mx + mTileW / 2, my);
11561
- mCtx.lineTo(mx + mTileW, my + mFloorH / 2);
11562
- mCtx.lineTo(mx + mTileW / 2, my + mFloorH);
11563
- mCtx.lineTo(mx, my + mFloorH / 2);
11564
- mCtx.closePath();
11565
- mCtx.fill();
11566
- }
11567
- for (const unit of units) {
11568
- if (!unit.position) continue;
11569
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11570
- const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
11571
- const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
11572
- mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
11573
- mCtx.beginPath();
11574
- mCtx.arc(mx, my, 3, 0, Math.PI * 2);
11575
- mCtx.fill();
11576
- }
11577
- const cam = cameraRef.current;
11578
- const vLeft = (cam.x - minX) * scaleM + offsetMx;
11579
- const vTop = (cam.y - minY) * scaleM + offsetMy;
11580
- const vW = viewportSize.width / cam.zoom * scaleM;
11581
- const vH = viewportSize.height / cam.zoom * scaleM;
11582
- mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
11583
- mCtx.lineWidth = 1;
11584
- mCtx.strokeRect(vLeft, vTop, vW, vH);
11585
- }, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
11586
- const draw = useCallback((animTime) => {
11409
+ return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
11410
+ }, [getUnitSprite, assetManifest]);
11411
+ const miniMapTiles = useMemo(() => {
11412
+ if (!showMinimap) return [];
11413
+ return sortedTiles.map((t2) => ({
11414
+ x: t2.x,
11415
+ y: t2.y,
11416
+ color: t2.terrain === "water" ? "#3b82f6" : t2.terrain === "mountain" ? "#78716c" : "#4ade80"
11417
+ }));
11418
+ }, [showMinimap, sortedTiles]);
11419
+ const miniMapUnits = useMemo(() => {
11420
+ if (!showMinimap) return [];
11421
+ return units.filter((u) => u.position).map((u) => ({
11422
+ x: u.position.x,
11423
+ y: u.position.y,
11424
+ color: u.team === "player" ? "#60a5fa" : u.team === "enemy" ? "#f87171" : "#9ca3af",
11425
+ isPlayer: u.team === "player"
11426
+ }));
11427
+ }, [showMinimap, units]);
11428
+ const miniMapWidth = gridWidth || 10;
11429
+ const miniMapHeight = gridHeight || 10;
11430
+ const draw = useCallback(() => {
11587
11431
  const canvas = canvasRef.current;
11588
11432
  if (!canvas) return;
11589
11433
  const ctx = canvas.getContext("2d");
@@ -11669,8 +11513,7 @@ function IsometricCanvas({
11669
11513
  if (validMoveSet.has(tileKey)) {
11670
11514
  const centerX = pos.x + scaledTileWidth / 2;
11671
11515
  const topY = pos.y + scaledDiamondTopY;
11672
- const pulse = 0.15 + 0.1 * Math.sin(animTime * 4e-3);
11673
- ctx.fillStyle = `rgba(74, 222, 128, ${pulse})`;
11516
+ ctx.fillStyle = "rgba(74, 222, 128, 0.25)";
11674
11517
  ctx.beginPath();
11675
11518
  ctx.moveTo(centerX, topY);
11676
11519
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -11682,8 +11525,7 @@ function IsometricCanvas({
11682
11525
  if (attackTargetSet.has(tileKey)) {
11683
11526
  const centerX = pos.x + scaledTileWidth / 2;
11684
11527
  const topY = pos.y + scaledDiamondTopY;
11685
- const pulse = 0.2 + 0.15 * Math.sin(animTime * 5e-3);
11686
- ctx.fillStyle = `rgba(239, 68, 68, ${pulse})`;
11528
+ ctx.fillStyle = "rgba(239, 68, 68, 0.35)";
11687
11529
  ctx.beginPath();
11688
11530
  ctx.moveTo(centerX, topY);
11689
11531
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -11712,7 +11554,7 @@ function IsometricCanvas({
11712
11554
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11713
11555
  continue;
11714
11556
  }
11715
- const spriteUrl = feature.sprite || resolveFeatureSpriteUrl(feature.type);
11557
+ const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
11716
11558
  const img = spriteUrl ? getImage(spriteUrl) : null;
11717
11559
  const centerX = pos.x + scaledTileWidth / 2;
11718
11560
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
@@ -11756,17 +11598,17 @@ function IsometricCanvas({
11756
11598
  const isSelected = unit.id === selectedUnitId;
11757
11599
  const centerX = pos.x + scaledTileWidth / 2;
11758
11600
  const groundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
11759
- const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
11601
+ const breatheOffset = 0;
11760
11602
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
11761
11603
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
11762
11604
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
11763
11605
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11606
+ const unitIsSheet = unit.sprite?.dimension === "2d" && (unit.sprite?.animations?.length ?? 0) > 0;
11764
11607
  const SHEET_ROWS = 5;
11765
11608
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
11766
11609
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11767
- const imgIsSheet = img ? img.naturalWidth % SHEET_COLUMNS === 0 && img.naturalHeight % SHEET_ROWS === 0 && Math.abs(sheetFrameW - sheetFrameH) < 2 : false;
11768
- const frameW = imgIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11769
- const frameH = imgIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11610
+ const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11611
+ const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11770
11612
  const ar = frameW / (frameH || 1);
11771
11613
  let drawH = unitDrawH;
11772
11614
  let drawW = unitDrawH * ar;
@@ -11781,7 +11623,7 @@ function IsometricCanvas({
11781
11623
  ctx.save();
11782
11624
  ctx.globalAlpha = 0.25;
11783
11625
  if (img) {
11784
- if (imgIsSheet) {
11626
+ if (unitIsSheet) {
11785
11627
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11786
11628
  } else {
11787
11629
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
@@ -11796,10 +11638,9 @@ function IsometricCanvas({
11796
11638
  ctx.restore();
11797
11639
  }
11798
11640
  if (isSelected) {
11799
- const ringAlpha = 0.6 + 0.3 * Math.sin(animTime * 4e-3);
11800
11641
  ctx.beginPath();
11801
11642
  ctx.ellipse(centerX, groundY, drawW / 2 + 4 * scale, 12 * scale, 0, 0, Math.PI * 2);
11802
- ctx.strokeStyle = `rgba(0, 200, 255, ${ringAlpha})`;
11643
+ ctx.strokeStyle = "rgba(0, 200, 255, 0.8)";
11803
11644
  ctx.lineWidth = 3;
11804
11645
  ctx.stroke();
11805
11646
  }
@@ -11830,7 +11671,7 @@ function IsometricCanvas({
11830
11671
  } else if (img) {
11831
11672
  const spriteY = groundY - drawH - breatheOffset;
11832
11673
  const drawUnit = (x) => {
11833
- if (imgIsSheet) {
11674
+ if (unitIsSheet) {
11834
11675
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11835
11676
  } else {
11836
11677
  ctx.drawImage(img, x, spriteY, drawW, drawH);
@@ -11855,66 +11696,29 @@ function IsometricCanvas({
11855
11696
  ctx.lineWidth = 2;
11856
11697
  ctx.stroke();
11857
11698
  }
11858
- if (unit.name) {
11859
- const labelBg = unit.team === "player" ? "rgba(59, 130, 246, 0.9)" : unit.team === "enemy" ? "rgba(239, 68, 68, 0.9)" : "rgba(107, 114, 128, 0.9)";
11860
- ctx.font = `bold ${10 * scale * 2.5}px system-ui`;
11861
- ctx.textAlign = "center";
11862
- const textWidth = ctx.measureText(unit.name).width;
11863
- const labelY = groundY + 14 * scale - breatheOffset;
11864
- ctx.fillStyle = labelBg;
11865
- ctx.beginPath();
11866
- ctx.roundRect(centerX - textWidth / 2 - 6 * scale, labelY - 8 * scale, textWidth + 12 * scale, 16 * scale, 4 * scale);
11867
- ctx.fill();
11868
- ctx.fillStyle = "white";
11869
- ctx.fillText(unit.name, centerX, labelY + 4 * scale);
11870
- }
11871
- if (unit.health !== void 0 && unit.maxHealth !== void 0) {
11872
- const barWidth = 40 * scale;
11873
- const barHeight = 6 * scale;
11874
- const barX = centerX - barWidth / 2;
11875
- const barY = groundY - drawH - 2 * scale - breatheOffset;
11876
- const healthRatio = unit.health / unit.maxHealth;
11877
- const barRadius = barHeight / 2;
11878
- ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
11879
- ctx.beginPath();
11880
- ctx.roundRect(barX, barY, barWidth, barHeight, barRadius);
11881
- ctx.fill();
11882
- if (healthRatio > 0) {
11883
- const fillWidth = barWidth * healthRatio;
11884
- const gradient = ctx.createLinearGradient(barX, barY, barX, barY + barHeight);
11885
- if (healthRatio > 0.6) {
11886
- gradient.addColorStop(0, "#4ade80");
11887
- gradient.addColorStop(1, "#22c55e");
11888
- } else if (healthRatio > 0.3) {
11889
- gradient.addColorStop(0, "#fde047");
11890
- gradient.addColorStop(1, "#eab308");
11891
- } else {
11892
- gradient.addColorStop(0, "#f87171");
11893
- gradient.addColorStop(1, "#ef4444");
11894
- }
11895
- ctx.fillStyle = gradient;
11896
- ctx.save();
11897
- ctx.beginPath();
11898
- ctx.roundRect(barX, barY, fillWidth, barHeight, barRadius);
11899
- ctx.clip();
11900
- ctx.fillRect(barX, barY, fillWidth, barHeight);
11901
- ctx.restore();
11902
- }
11903
- ctx.strokeStyle = "rgba(255, 255, 255, 0.3)";
11904
- ctx.lineWidth = 1;
11905
- ctx.beginPath();
11906
- ctx.roundRect(barX, barY, barWidth, barHeight, barRadius);
11907
- ctx.stroke();
11908
- }
11909
11699
  }
11910
- onDrawEffects?.(ctx, animTime, getImage);
11700
+ for (const fx of effects) {
11701
+ const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
11702
+ if (!spriteUrl) continue;
11703
+ const img = getImage(spriteUrl);
11704
+ if (!img) continue;
11705
+ const pos = isoToScreen(fx.x, fx.y, scale, baseOffsetX, tileLayout);
11706
+ const cx = pos.x + scaledTileWidth / 2;
11707
+ const cy = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
11708
+ const alpha = Math.min(1, fx.ttl / 4);
11709
+ const prev = ctx.globalAlpha;
11710
+ ctx.globalAlpha = alpha;
11711
+ ctx.drawImage(img, cx - img.naturalWidth / 2, cy - img.naturalHeight / 2);
11712
+ ctx.globalAlpha = prev;
11713
+ }
11714
+ onDrawEffects?.(ctx, 0, getImage);
11911
11715
  ctx.restore();
11912
- drawMinimap();
11913
11716
  }, [
11914
11717
  sortedTiles,
11915
11718
  units,
11916
11719
  features,
11917
11720
  selectedUnitId,
11721
+ effects,
11918
11722
  tileLayout,
11919
11723
  scale,
11920
11724
  debug2,
@@ -11934,11 +11738,11 @@ function IsometricCanvas({
11934
11738
  attackTargetSet,
11935
11739
  hoveredTile,
11936
11740
  viewportSize,
11937
- drawMinimap,
11938
11741
  onDrawEffects,
11939
11742
  backgroundImage,
11940
11743
  cameraRef,
11941
- unitScale
11744
+ unitScale,
11745
+ assetManifest
11942
11746
  ]);
11943
11747
  useEffect(() => {
11944
11748
  if (!selectedUnitId) return;
@@ -11953,30 +11757,33 @@ function IsometricCanvas({
11953
11757
  };
11954
11758
  }, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11955
11759
  useEffect(() => {
11956
- const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
11957
- draw(animTimeRef.current);
11958
- if (!hasAnimations) return;
11760
+ draw();
11761
+ }, [draw]);
11762
+ useEffect(() => {
11763
+ draw();
11764
+ }, [_imagePendingCount]);
11765
+ useEffect(() => {
11766
+ if (selectedUnitId == null) return;
11959
11767
  let running = true;
11960
- const animate = (timestamp) => {
11768
+ const tick = () => {
11961
11769
  if (!running) return;
11962
- animTimeRef.current = timestamp;
11963
- lerpToTarget();
11964
- draw(timestamp);
11965
- rafIdRef.current = requestAnimationFrame(animate);
11770
+ const stillLerping = lerpToTarget();
11771
+ draw();
11772
+ if (stillLerping) lerpRafRef.current = requestAnimationFrame(tick);
11966
11773
  };
11967
- rafIdRef.current = requestAnimationFrame(animate);
11774
+ lerpRafRef.current = requestAnimationFrame(tick);
11968
11775
  return () => {
11969
11776
  running = false;
11970
- cancelAnimationFrame(rafIdRef.current);
11777
+ cancelAnimationFrame(lerpRafRef.current);
11971
11778
  };
11972
- }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
11779
+ }, [selectedUnitId, lerpToTarget, draw]);
11973
11780
  const singlePointerActiveRef = useRef(false);
11974
11781
  const handleCanvasPointerDown = useCallback((e) => {
11975
11782
  singlePointerActiveRef.current = true;
11976
11783
  if (enableCamera) handlePointerDown(e);
11977
11784
  }, [enableCamera, handlePointerDown]);
11978
11785
  const handleCanvasPointerMove = useCallback((e) => {
11979
- if (enableCamera) handlePointerMove(e, () => draw(animTimeRef.current));
11786
+ if (enableCamera) handlePointerMove(e, () => draw());
11980
11787
  }, [enableCamera, handlePointerMove, draw]);
11981
11788
  const handleCanvasHover = useCallback((e) => {
11982
11789
  if (singlePointerActiveRef.current) return;
@@ -12018,10 +11825,10 @@ function IsometricCanvas({
12018
11825
  onTileLeave?.();
12019
11826
  }, [handleMouseLeave, onTileLeave, tileLeaveEvent, eventBus]);
12020
11827
  const applyZoom = useCallback((factor, centerX, centerY) => {
12021
- if (enableCamera) zoomAtPoint(factor, centerX, centerY, viewportSize, () => draw(animTimeRef.current));
11828
+ if (enableCamera) zoomAtPoint(factor, centerX, centerY, viewportSize, () => draw());
12022
11829
  }, [enableCamera, zoomAtPoint, viewportSize, draw]);
12023
11830
  const applyPanDelta = useCallback((dx, dy) => {
12024
- if (enableCamera) panBy(dx, dy, () => draw(animTimeRef.current));
11831
+ if (enableCamera) panBy(dx, dy, () => draw());
12025
11832
  }, [enableCamera, panBy, draw]);
12026
11833
  const cancelSinglePointer = useCallback(() => {
12027
11834
  singlePointerActiveRef.current = false;
@@ -12037,11 +11844,27 @@ function IsometricCanvas({
12037
11844
  onPanDelta: applyPanDelta,
12038
11845
  onMultiTouchStart: cancelSinglePointer
12039
11846
  });
11847
+ const unitOverlays = useMemo(() => {
11848
+ if (sortedTiles.length === 0) return [];
11849
+ return units.filter((u) => !!u.position).map((u) => {
11850
+ const pos = isoToScreen(u.position.x, u.position.y, scale, baseOffsetX, tileLayout);
11851
+ const cam = cameraRef.current;
11852
+ const screenX = (pos.x + scaledTileWidth / 2 - (cam.x + viewportSize.width / 2)) * cam.zoom + viewportSize.width / 2;
11853
+ const screenY = (pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5 - (cam.y + viewportSize.height / 2)) * cam.zoom + viewportSize.height / 2;
11854
+ return { unit: u, screenX, screenY };
11855
+ });
11856
+ }, [units, sortedTiles.length, scale, baseOffsetX, tileLayout, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, cameraRef]);
12040
11857
  if (error) {
12041
- return /* @__PURE__ */ jsx(ErrorState, { title: t("canvas.errorTitle"), message: error.message, className });
11858
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center w-full h-full bg-[var(--color-card)] rounded-container", className), children: /* @__PURE__ */ jsxs(Stack, { direction: "vertical", gap: "md", align: "center", children: [
11859
+ /* @__PURE__ */ jsx(Icon, { name: "alert-circle", size: "xl" }),
11860
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-error", children: error.message })
11861
+ ] }) });
12042
11862
  }
12043
11863
  if (isLoading) {
12044
- return /* @__PURE__ */ jsx(LoadingState, { className });
11864
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center w-full h-full bg-[var(--color-card)] rounded-container", className), children: /* @__PURE__ */ jsxs(Stack, { direction: "vertical", gap: "md", align: "center", children: [
11865
+ /* @__PURE__ */ jsx(Icon, { name: "loader", size: "xl", className: "animate-spin" }),
11866
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-muted-foreground", children: t("canvas.loadingMessage") || "Loading\u2026" })
11867
+ ] }) });
12045
11868
  }
12046
11869
  if (sortedTiles.length === 0) {
12047
11870
  return /* @__PURE__ */ jsx(
@@ -12106,14 +11929,36 @@ function IsometricCanvas({
12106
11929
  }
12107
11930
  )
12108
11931
  ] }),
12109
- showMinimap && /* @__PURE__ */ jsx(
12110
- "canvas",
11932
+ unitOverlays.map(({ unit, screenX, screenY }) => /* @__PURE__ */ jsxs(
11933
+ "div",
12111
11934
  {
12112
- ref: minimapRef,
12113
- className: "absolute bottom-2 right-2 border border-border rounded bg-background/80 pointer-events-none",
12114
- style: { width: 150, height: 100, zIndex: 10 }
11935
+ className: "absolute pointer-events-none",
11936
+ style: { left: Math.round(screenX), top: Math.round(screenY), transform: "translate(-50%, 0)", zIndex: 5 },
11937
+ children: [
11938
+ unit.name && /* @__PURE__ */ jsx(
11939
+ "div",
11940
+ {
11941
+ className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap",
11942
+ style: { background: unit.team === "player" ? "rgba(59,130,246,0.9)" : unit.team === "enemy" ? "rgba(239,68,68,0.9)" : "rgba(107,114,128,0.9)" },
11943
+ children: unit.name
11944
+ }
11945
+ ),
11946
+ unit.health !== void 0 && unit.maxHealth !== void 0 && unit.maxHealth > 0 && /* @__PURE__ */ jsx(HealthBar, { current: unit.health, max: unit.maxHealth, format: "bar", size: "sm" })
11947
+ ]
11948
+ },
11949
+ unit.id
11950
+ )),
11951
+ showMinimap && /* @__PURE__ */ jsx("div", { className: "absolute bottom-2 right-2 pointer-events-none", style: { zIndex: 10 }, children: /* @__PURE__ */ jsx(
11952
+ MiniMap,
11953
+ {
11954
+ tiles: miniMapTiles,
11955
+ units: miniMapUnits,
11956
+ width: 150,
11957
+ height: 100,
11958
+ mapWidth: miniMapWidth,
11959
+ mapHeight: miniMapHeight
12115
11960
  }
12116
- )
11961
+ ) })
12117
11962
  ]
12118
11963
  }
12119
11964
  );
@@ -12128,8 +11973,8 @@ var init_IsometricCanvas = __esm({
12128
11973
  init_Stack();
12129
11974
  init_Icon();
12130
11975
  init_Typography();
12131
- init_LoadingState();
12132
- init_ErrorState();
11976
+ init_MiniMap();
11977
+ init_HealthBar();
12133
11978
  init_useImageCache();
12134
11979
  init_useCamera();
12135
11980
  init_useCanvasGestures();
@@ -12174,6 +12019,42 @@ var init_boardEntity = __esm({
12174
12019
  "components/game/organisms/boardEntity.ts"() {
12175
12020
  }
12176
12021
  });
12022
+
12023
+ // components/game/organisms/utils/makeAsset.ts
12024
+ function makeAsset(url, role, overrides = {}) {
12025
+ const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
12026
+ return {
12027
+ url,
12028
+ role,
12029
+ category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
12030
+ ...defaults,
12031
+ ...overrides
12032
+ };
12033
+ }
12034
+ function makeAssetMap(record, role, overrides = {}) {
12035
+ const result = {};
12036
+ for (const [key, url] of Object.entries(record)) {
12037
+ result[key] = makeAsset(url, role, overrides);
12038
+ }
12039
+ return result;
12040
+ }
12041
+ var ROLE_DEFAULTS;
12042
+ var init_makeAsset = __esm({
12043
+ "components/game/organisms/utils/makeAsset.ts"() {
12044
+ ROLE_DEFAULTS = {
12045
+ tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12046
+ decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12047
+ effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12048
+ item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
12049
+ player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12050
+ enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12051
+ npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12052
+ projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12053
+ vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
12054
+ ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
12055
+ };
12056
+ }
12057
+ });
12177
12058
  function buildDefaultBattleTiles() {
12178
12059
  const tiles = [];
12179
12060
  for (let y = 0; y < BATTLE_GRID_H; y++) {
@@ -12232,14 +12113,14 @@ function BattleBoard({
12232
12113
  if (o === null || typeof o.x !== "number" || typeof o.y !== "number") return [];
12233
12114
  const tile = { x: o.x, y: o.y };
12234
12115
  if (typeof o.terrain === "string") tile.terrain = o.terrain;
12235
- if (typeof o.terrainSprite === "string") tile.terrainSprite = o.terrainSprite;
12116
+ if (typeof o.terrainSprite === "string") tile.terrainSprite = makeAsset(o.terrainSprite, "tile");
12236
12117
  if (typeof o.passable === "boolean") tile.passable = o.passable;
12237
12118
  if (typeof o.movementCost === "number") tile.movementCost = o.movementCost;
12238
12119
  if (typeof o.elevation === "number") tile.elevation = o.elevation;
12239
12120
  if (typeof o.type === "string") tile.type = o.type;
12240
12121
  if (typeof o.tileType === "string") tile.tileType = o.tileType;
12241
12122
  if (typeof o.id === "string") tile.id = o.id;
12242
- if (typeof o.modelUrl === "string") tile.modelUrl = o.modelUrl;
12123
+ if (typeof o.modelUrl === "string") tile.modelUrl = makeAsset(o.modelUrl, "decoration", { dimension: "3d" });
12243
12124
  return [tile];
12244
12125
  }) : []);
12245
12126
  const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
@@ -12248,10 +12129,10 @@ function BattleBoard({
12248
12129
  if (o === null || typeof o.type !== "string" || typeof o.x !== "number" || typeof o.y !== "number") return [];
12249
12130
  const feat = { type: o.type, x: o.x, y: o.y };
12250
12131
  if (typeof o.id === "string") feat.id = o.id;
12251
- if (typeof o.sprite === "string") feat.sprite = o.sprite;
12132
+ if (typeof o.sprite === "string") feat.sprite = makeAsset(o.sprite, "decoration");
12252
12133
  if (typeof o.color === "string") feat.color = o.color;
12253
12134
  if (typeof o.elevation === "number") feat.elevation = o.elevation;
12254
- if (typeof o.assetUrl === "string") feat.assetUrl = o.assetUrl;
12135
+ if (typeof o.assetUrl === "string") feat.assetUrl = makeAsset(o.assetUrl, "decoration", { dimension: "3d" });
12255
12136
  return [feat];
12256
12137
  }) : []);
12257
12138
  const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
@@ -12367,7 +12248,7 @@ function BattleBoard({
12367
12248
  maxHealth: num(unit.maxHealth),
12368
12249
  unitType: unit.unitType == null ? void 0 : str(unit.unitType),
12369
12250
  heroId: unit.heroId == null ? void 0 : str(unit.heroId),
12370
- sprite: unit.sprite == null ? void 0 : str(unit.sprite),
12251
+ sprite: unit.sprite == null ? void 0 : makeAsset(str(unit.sprite), "npc"),
12371
12252
  traits: unitTraits?.map((tr) => ({
12372
12253
  name: tr.name,
12373
12254
  currentState: tr.currentState,
@@ -12517,7 +12398,6 @@ function BattleBoard({
12517
12398
  onTileHover: (x, y) => setHoveredTile({ x, y }),
12518
12399
  onTileLeave: () => setHoveredTile(null),
12519
12400
  scale,
12520
- assetBaseUrl: assetManifest?.baseUrl,
12521
12401
  assetManifest,
12522
12402
  backgroundImage,
12523
12403
  onDrawEffects,
@@ -12595,15 +12475,16 @@ var init_BattleBoard = __esm({
12595
12475
  init_IsometricCanvas();
12596
12476
  init_boardEntity();
12597
12477
  init_isometric();
12478
+ init_makeAsset();
12598
12479
  BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
12599
12480
  BATTLE_GRID_W = 16;
12600
12481
  BATTLE_GRID_H = 16;
12601
12482
  BATTLE_TERRAIN_SPRITES = [
12602
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
12603
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
12604
- `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
12605
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
12606
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
12483
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`, "tile"),
12484
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile"),
12485
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`, "tile"),
12486
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, "tile"),
12487
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile")
12607
12488
  ];
12608
12489
  DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
12609
12490
  BattleBoard.displayName = "BattleBoard";
@@ -12642,61 +12523,64 @@ function BattleTemplate({
12642
12523
  }
12643
12524
  );
12644
12525
  }
12645
- var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12526
+ var CDN, STONE, DIRT, GRASS, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12646
12527
  var init_BattleTemplate = __esm({
12647
12528
  "components/game/templates/BattleTemplate.tsx"() {
12648
12529
  init_BattleBoard();
12530
+ init_makeAsset();
12649
12531
  CDN = "https://almadar-kflow-assets.web.app/shared";
12532
+ STONE = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`, "tile");
12533
+ DIRT = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`, "tile");
12534
+ GRASS = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`, "tile");
12650
12535
  DEFAULT_BATTLE_TILES2 = [
12651
- { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12652
- { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12653
- { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12654
- { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12655
- { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12656
- { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12657
- { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12658
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12659
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12660
- { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12661
- { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12662
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12663
- { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12664
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12665
- { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12666
- { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12667
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12668
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12669
- { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12670
- { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12671
- { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12672
- { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12673
- { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12674
- { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12675
- { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` }
12536
+ { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12537
+ { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12538
+ { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12539
+ { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12540
+ { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12541
+ { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
12542
+ { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: DIRT },
12543
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
12544
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
12545
+ { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
12546
+ { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
12547
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
12548
+ { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: DIRT },
12549
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
12550
+ { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
12551
+ { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
12552
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
12553
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
12554
+ { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: DIRT },
12555
+ { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
12556
+ { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12557
+ { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12558
+ { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12559
+ { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12560
+ { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: STONE }
12676
12561
  ];
12677
12562
  DEFAULT_BATTLE_UNITS = [
12678
- { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png` },
12679
- { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "enemy", health: 8, maxHealth: 10, sprite: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png` }
12563
+ { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN}/sprite-sheets/amir-sprite-sheet-se.png`, "player") },
12564
+ { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "enemy", health: 8, maxHealth: 10, sprite: makeAsset(`${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`, "enemy") }
12680
12565
  ];
12681
12566
  DEFAULT_BATTLE_FEATURES = [
12682
- { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: `${CDN}/world-map/gold_mine.png` },
12683
- { id: "f2", x: 3, y: 1, type: "portal", sprite: `${CDN}/world-map/portal_open.png` }
12567
+ { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: makeAsset(`${CDN}/world-map/gold_mine.png`, "decoration") },
12568
+ { id: "f2", x: 3, y: 1, type: "portal", sprite: makeAsset(`${CDN}/world-map/portal_open.png`, "decoration") }
12684
12569
  ];
12685
12570
  DEFAULT_BATTLE_MANIFEST = {
12686
- baseUrl: CDN,
12687
- terrains: {
12688
- stone: "/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png",
12689
- dirt: "/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png",
12690
- grass: "/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png"
12691
- },
12692
- units: {
12693
- worker: "/sprite-sheets/amir-sprite-sheet-se.png",
12694
- guardian: "/sprite-sheets/destroyer-sprite-sheet-sw.png"
12695
- },
12696
- features: {
12697
- gold_mine: "/world-map/gold_mine.png",
12698
- portal: "/world-map/portal_open.png"
12699
- }
12571
+ terrains: makeAssetMap({
12572
+ stone: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`,
12573
+ dirt: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`,
12574
+ grass: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`
12575
+ }, "tile"),
12576
+ units: makeAssetMap({
12577
+ worker: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png`,
12578
+ guardian: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`
12579
+ }, "npc"),
12580
+ features: makeAssetMap({
12581
+ gold_mine: `${CDN}/world-map/gold_mine.png`,
12582
+ portal: `${CDN}/world-map/portal_open.png`
12583
+ }, "decoration")
12700
12584
  };
12701
12585
  BattleTemplate.displayName = "BattleTemplate";
12702
12586
  }
@@ -13687,6 +13571,50 @@ var init_Tabs = __esm({
13687
13571
  Tabs.displayName = "Tabs";
13688
13572
  }
13689
13573
  });
13574
+ var LoadingState;
13575
+ var init_LoadingState = __esm({
13576
+ "components/core/molecules/LoadingState.tsx"() {
13577
+ "use client";
13578
+ init_cn();
13579
+ init_atoms2();
13580
+ init_Stack();
13581
+ init_Typography();
13582
+ LoadingState = ({
13583
+ title,
13584
+ message,
13585
+ className
13586
+ }) => {
13587
+ const { t } = useTranslate();
13588
+ const displayMessage = message ?? t("common.loading");
13589
+ return /* @__PURE__ */ jsxs(
13590
+ VStack,
13591
+ {
13592
+ align: "center",
13593
+ className: cn(
13594
+ "justify-center py-12",
13595
+ className
13596
+ ),
13597
+ children: [
13598
+ /* @__PURE__ */ jsx(Spinner, { size: "lg" }),
13599
+ title && /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "mt-4 text-lg font-semibold text-foreground", children: title }),
13600
+ /* @__PURE__ */ jsx(
13601
+ Typography,
13602
+ {
13603
+ variant: "small",
13604
+ className: cn(
13605
+ "text-muted-foreground",
13606
+ title ? "mt-2" : "mt-4"
13607
+ ),
13608
+ children: displayMessage
13609
+ }
13610
+ )
13611
+ ]
13612
+ }
13613
+ );
13614
+ };
13615
+ LoadingState.displayName = "LoadingState";
13616
+ }
13617
+ });
13690
13618
  var ICON_NAME_ALIASES, lookStyles3, EmptyState;
13691
13619
  var init_EmptyState = __esm({
13692
13620
  "components/core/molecules/EmptyState.tsx"() {
@@ -13967,7 +13895,7 @@ var init_CodeBlock = __esm({
13967
13895
  };
13968
13896
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
13969
13897
  HIDDEN_LINE_NUMBERS = { display: "none" };
13970
- CodeBlock = React90__default.memo(
13898
+ CodeBlock = React88__default.memo(
13971
13899
  ({
13972
13900
  code: rawCode,
13973
13901
  language = "text",
@@ -14554,7 +14482,7 @@ var init_MarkdownContent = __esm({
14554
14482
  init_Box();
14555
14483
  init_CodeBlock();
14556
14484
  init_cn();
14557
- MarkdownContent = React90__default.memo(
14485
+ MarkdownContent = React88__default.memo(
14558
14486
  ({ content, direction = "ltr", className }) => {
14559
14487
  const { t: _t } = useTranslate();
14560
14488
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -14867,7 +14795,6 @@ function BoardgameBoard({
14867
14795
  units,
14868
14796
  features,
14869
14797
  assetManifest,
14870
- assetBaseUrl,
14871
14798
  scale,
14872
14799
  showMinimap,
14873
14800
  enableCamera,
@@ -15923,7 +15850,7 @@ var init_StateMachineView = __esm({
15923
15850
  style: { top: title ? 30 : 0 },
15924
15851
  children: [
15925
15852
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
15926
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React90__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
15853
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React88__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
15927
15854
  StateNode,
15928
15855
  {
15929
15856
  state,
@@ -19892,7 +19819,7 @@ function CardHand({
19892
19819
  className
19893
19820
  }) {
19894
19821
  const eventBus = useEventBus();
19895
- const handleClick = React90.useCallback(
19822
+ const handleClick = React88.useCallback(
19896
19823
  (card) => {
19897
19824
  if (card.disabled) return;
19898
19825
  onCardClick?.(card.id);
@@ -19937,7 +19864,7 @@ function CardHand({
19937
19864
  /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
19938
19865
  "img",
19939
19866
  {
19940
- src: card.iconUrl,
19867
+ src: card.iconUrl.url,
19941
19868
  alt: card.title ?? card.id,
19942
19869
  width: art,
19943
19870
  height: art,
@@ -19995,15 +19922,6 @@ var init_CardHand = __esm({
19995
19922
  CardHand.displayName = "CardHand";
19996
19923
  }
19997
19924
  });
19998
- function resolveManifestUrl(manifest, relative) {
19999
- if (relative == null) return void 0;
20000
- if (/^https?:\/\//.test(relative)) return relative;
20001
- const base = manifest?.baseUrl;
20002
- if (base == null) return relative;
20003
- const cleanBase = base.replace(/\/$/, "");
20004
- const cleanRel = relative.replace(/^\//, "");
20005
- return `${cleanBase}/${cleanRel}`;
20006
- }
20007
19925
  function rowToCard(r) {
20008
19926
  return {
20009
19927
  id: str(r.id),
@@ -20017,7 +19935,7 @@ function rowToCard(r) {
20017
19935
  function toHandCards(cards, manifest, mana) {
20018
19936
  return cards.map((c) => {
20019
19937
  const key = c.iconKey ?? c.id;
20020
- const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
19938
+ const iconUrl = manifest?.cards?.[key];
20021
19939
  return {
20022
19940
  id: c.id,
20023
19941
  iconUrl,
@@ -21131,7 +21049,6 @@ function CastleBoard({
21131
21049
  onTileHover: (x, y) => setHoveredTile({ x, y }),
21132
21050
  onTileLeave: () => setHoveredTile(null),
21133
21051
  scale,
21134
- assetBaseUrl: assetManifest?.baseUrl,
21135
21052
  assetManifest,
21136
21053
  backgroundImage
21137
21054
  }
@@ -21207,60 +21124,63 @@ function CastleTemplate({
21207
21124
  }
21208
21125
  );
21209
21126
  }
21210
- var CDN2, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
21127
+ var CDN2, WALL, FLOOR, FLOOR_CENTER, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
21211
21128
  var init_CastleTemplate = __esm({
21212
21129
  "components/game/templates/CastleTemplate.tsx"() {
21213
21130
  init_CastleBoard();
21131
+ init_makeAsset();
21214
21132
  CDN2 = "https://almadar-kflow-assets.web.app/shared";
21133
+ WALL = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`, "tile");
21134
+ FLOOR = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
21135
+ FLOOR_CENTER = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`, "tile");
21215
21136
  DEFAULT_CASTLE_TILES = [
21216
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21217
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21218
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21219
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21220
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21221
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21222
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21223
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21224
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21225
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21226
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21227
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21228
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png` },
21229
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21230
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21231
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21232
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21233
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21234
- { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21235
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21236
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21237
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21238
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21239
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21240
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` }
21137
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21138
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21139
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21140
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21141
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21142
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
21143
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21144
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21145
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21146
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
21147
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
21148
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
21149
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR_CENTER },
21150
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
21151
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
21152
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
21153
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21154
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21155
+ { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21156
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
21157
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21158
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21159
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21160
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21161
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: WALL }
21241
21162
  ];
21242
21163
  DEFAULT_CASTLE_UNITS = [
21243
- { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png` },
21244
- { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "player", health: 10, maxHealth: 10, sprite: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png` }
21164
+ { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`, "player") },
21165
+ { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`, "player") }
21245
21166
  ];
21246
21167
  DEFAULT_CASTLE_FEATURES = [
21247
- { id: "f1", x: 2, y: 2, type: "chest", sprite: `${CDN2}/world-map/treasure_chest_closed.png` },
21248
- { id: "f2", x: 3, y: 1, type: "crystal", sprite: `${CDN2}/world-map/resonance_crystal.png` }
21168
+ { id: "f1", x: 2, y: 2, type: "chest", sprite: makeAsset(`${CDN2}/world-map/treasure_chest_closed.png`, "decoration") },
21169
+ { id: "f2", x: 3, y: 1, type: "crystal", sprite: makeAsset(`${CDN2}/world-map/resonance_crystal.png`, "decoration") }
21249
21170
  ];
21250
21171
  DEFAULT_CASTLE_MANIFEST = {
21251
- baseUrl: CDN2,
21252
- terrains: {
21253
- wall: "/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png",
21254
- floor: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png"
21255
- },
21256
- units: {
21257
- worker: "/sprite-sheets/coordinator-sprite-sheet-se.png",
21258
- guardian: "/sprite-sheets/forger-sprite-sheet-se.png"
21259
- },
21260
- features: {
21261
- chest: "/world-map/treasure_chest_closed.png",
21262
- crystal: "/world-map/resonance_crystal.png"
21263
- }
21172
+ terrains: makeAssetMap({
21173
+ wall: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
21174
+ floor: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`
21175
+ }, "tile"),
21176
+ units: makeAssetMap({
21177
+ worker: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`,
21178
+ guardian: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`
21179
+ }, "player"),
21180
+ features: makeAssetMap({
21181
+ chest: `${CDN2}/world-map/treasure_chest_closed.png`,
21182
+ crystal: `${CDN2}/world-map/resonance_crystal.png`
21183
+ }, "decoration")
21264
21184
  };
21265
21185
  CastleTemplate.displayName = "CastleTemplate";
21266
21186
  }
@@ -22248,15 +22168,6 @@ var init_ChatBar = __esm({
22248
22168
  ChatBar.displayName = "ChatBar";
22249
22169
  }
22250
22170
  });
22251
- function resolveManifestUrl2(manifest, relative) {
22252
- if (relative == null) return void 0;
22253
- if (/^https?:\/\//.test(relative)) return relative;
22254
- const base = manifest?.baseUrl;
22255
- if (base == null) return relative;
22256
- const cleanBase = base.replace(/\/$/, "");
22257
- const cleanRel = relative.replace(/^\//, "");
22258
- return `${cleanBase}/${cleanRel}`;
22259
- }
22260
22171
  function buildDefaultCBTiles() {
22261
22172
  const tiles = [];
22262
22173
  for (let y = 0; y < CB_GRID_H; y++) {
@@ -22271,12 +22182,12 @@ function buildDefaultCBTiles() {
22271
22182
  function tilesToIso(tiles, manifest) {
22272
22183
  return tiles.map((t) => {
22273
22184
  const key = t.terrain ?? "grass";
22274
- const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
22185
+ const terrainSprite = t.terrainSprite ?? manifest?.terrains?.[key] ?? manifest?.terrains?.grass;
22275
22186
  return {
22276
22187
  x: t.x,
22277
22188
  y: t.y,
22278
22189
  terrain: t.terrain,
22279
- terrainSprite: sprite,
22190
+ terrainSprite,
22280
22191
  passable: t.passable
22281
22192
  };
22282
22193
  });
@@ -22287,7 +22198,7 @@ function buildingsToFeatures(buildings, manifest) {
22287
22198
  x: b.x,
22288
22199
  y: b.y,
22289
22200
  type: b.type,
22290
- sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
22201
+ sprite: manifest?.features?.[b.type]
22291
22202
  }));
22292
22203
  }
22293
22204
  function CityBuilderBoard({
@@ -22319,7 +22230,7 @@ function CityBuilderBoard({
22319
22230
  x: num(r.x),
22320
22231
  y: num(r.y),
22321
22232
  terrain: r.terrain == null ? void 0 : str(r.terrain),
22322
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
22233
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
22323
22234
  passable: r.passable !== false
22324
22235
  })),
22325
22236
  [board.tiles]
@@ -22428,7 +22339,6 @@ function CityBuilderBoard({
22428
22339
  {
22429
22340
  tiles: isoTiles,
22430
22341
  features: buildingFeatures,
22431
- assetBaseUrl: assetManifest?.baseUrl,
22432
22342
  assetManifest,
22433
22343
  validMoves,
22434
22344
  hoveredTile,
@@ -22463,6 +22373,7 @@ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
22463
22373
  var init_CityBuilderBoard = __esm({
22464
22374
  "components/game/organisms/CityBuilderBoard.tsx"() {
22465
22375
  "use client";
22376
+ init_makeAsset();
22466
22377
  init_cn();
22467
22378
  init_useEventBus();
22468
22379
  init_Box();
@@ -22881,10 +22792,10 @@ function CombatLog({
22881
22792
  }, [events2, autoScroll]);
22882
22793
  const safeEvents = events2 ?? [];
22883
22794
  const visibleEvents = safeEvents.slice(-maxVisible);
22884
- return /* @__PURE__ */ jsxs(Card, { variant: "default", className: cn("flex flex-col", className), children: [
22795
+ return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col rounded-container border border-border bg-card shadow-elevation-card", className), children: [
22885
22796
  /* @__PURE__ */ jsx(Box, { padding: "sm", border: true, className: "border-b-2 border-x-0 border-t-0 border-border", children: /* @__PURE__ */ jsxs(Box, { display: "flex", className: "items-center justify-between", children: [
22886
22797
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "font-bold", children: title }),
22887
- /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
22798
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground bg-muted/60 rounded px-1.5 py-0.5 border border-border/50 font-mono", children: [
22888
22799
  safeEvents.length,
22889
22800
  " events"
22890
22801
  ] })
@@ -22904,7 +22815,7 @@ function CombatLog({
22904
22815
  /* @__PURE__ */ jsx(Box, { className: cn("flex-shrink-0 mt-0.5", colorClass), children: /* @__PURE__ */ jsx(EventIcon, { className: "h-4 w-4" }) }),
22905
22816
  /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
22906
22817
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "block", children: event.message }),
22907
- event.value !== void 0 && /* @__PURE__ */ jsxs(Badge, { variant: eventBadgeVariants[eventType], size: "sm", className: "mt-1", children: [
22818
+ event.value !== void 0 && /* @__PURE__ */ jsxs("span", { className: cn("inline-block mt-1 text-xs font-bold rounded px-1.5 py-0.5 border", eventValueColors[eventType]), children: [
22908
22819
  eventType === "heal" ? "+" : eventType === "attack" ? "-" : "",
22909
22820
  event.value
22910
22821
  ] })
@@ -22917,7 +22828,7 @@ function CombatLog({
22917
22828
  }) }) })
22918
22829
  ] });
22919
22830
  }
22920
- var eventIcons, eventColors, eventBadgeVariants, DEFAULT_COMBAT_EVENTS;
22831
+ var eventIcons, eventColors, eventValueColors, DEFAULT_COMBAT_EVENTS;
22921
22832
  var init_CombatLog = __esm({
22922
22833
  "components/game/molecules/CombatLog.tsx"() {
22923
22834
  init_atoms2();
@@ -22940,14 +22851,14 @@ var init_CombatLog = __esm({
22940
22851
  death: "text-muted-foreground",
22941
22852
  spawn: "text-accent"
22942
22853
  };
22943
- eventBadgeVariants = {
22944
- attack: "danger",
22945
- defend: "primary",
22946
- heal: "success",
22947
- move: "warning",
22948
- special: "secondary",
22949
- death: "secondary",
22950
- spawn: "secondary"
22854
+ eventValueColors = {
22855
+ attack: "text-error bg-error/10 border-error/30",
22856
+ defend: "text-info bg-info/10 border-info/30",
22857
+ heal: "text-success bg-success/10 border-success/30",
22858
+ move: "text-warning bg-warning/10 border-warning/30",
22859
+ special: "text-accent bg-accent/10 border-accent/30",
22860
+ death: "text-muted-foreground bg-muted/30 border-border",
22861
+ spawn: "text-accent bg-accent/10 border-accent/30"
22951
22862
  };
22952
22863
  DEFAULT_COMBAT_EVENTS = [
22953
22864
  { id: "e1", type: "spawn", message: "Shadow Guard entered the field.", timestamp: 0, turn: 1 },
@@ -23371,7 +23282,7 @@ function CraftingRecipe({
23371
23282
  className
23372
23283
  }) {
23373
23284
  const eventBus = useEventBus();
23374
- const handleCraft = React90.useCallback(() => {
23285
+ const handleCraft = React88.useCallback(() => {
23375
23286
  onCraft?.();
23376
23287
  if (craftEvent) {
23377
23288
  eventBus.emit(craftEvent, { output: output.label });
@@ -23388,7 +23299,7 @@ function CraftingRecipe({
23388
23299
  children: [
23389
23300
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
23390
23301
  const hasSufficient = ingredient.available >= ingredient.required;
23391
- return /* @__PURE__ */ jsxs(React90.Fragment, { children: [
23302
+ return /* @__PURE__ */ jsxs(React88.Fragment, { children: [
23392
23303
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
23393
23304
  ItemSlot,
23394
23305
  {
@@ -23413,13 +23324,13 @@ function CraftingRecipe({
23413
23324
  }
23414
23325
  ),
23415
23326
  /* @__PURE__ */ jsx(
23416
- Button,
23327
+ ActionButton,
23417
23328
  {
23329
+ label: "Craft",
23418
23330
  onClick: handleCraft,
23419
23331
  disabled: !canCraft,
23420
23332
  variant: canCraft ? "primary" : "secondary",
23421
- size: "sm",
23422
- children: "Craft"
23333
+ size: "sm"
23423
23334
  }
23424
23335
  )
23425
23336
  ]
@@ -23433,7 +23344,7 @@ var init_CraftingRecipe = __esm({
23433
23344
  init_cn();
23434
23345
  init_useEventBus();
23435
23346
  init_ItemSlot();
23436
- init_Button();
23347
+ init_ActionButton();
23437
23348
  init_Box();
23438
23349
  init_Stack();
23439
23350
  init_Icon();
@@ -23460,8 +23371,8 @@ function DPad({
23460
23371
  }) {
23461
23372
  const eventBus = useEventBus();
23462
23373
  const sizes = sizeMap15[size];
23463
- const [activeDirections, setActiveDirections] = React90.useState(/* @__PURE__ */ new Set());
23464
- const handlePress = React90.useCallback(
23374
+ const [activeDirections, setActiveDirections] = React88.useState(/* @__PURE__ */ new Set());
23375
+ const handlePress = React88.useCallback(
23465
23376
  (direction) => {
23466
23377
  setActiveDirections((prev) => new Set(prev).add(direction));
23467
23378
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -23469,7 +23380,7 @@ function DPad({
23469
23380
  },
23470
23381
  [directionEvent, eventBus, onDirection]
23471
23382
  );
23472
- const handleRelease = React90.useCallback(
23383
+ const handleRelease = React88.useCallback(
23473
23384
  (direction) => {
23474
23385
  setActiveDirections((prev) => {
23475
23386
  const next = new Set(prev);
@@ -24354,8 +24265,8 @@ var init_Menu = __esm({
24354
24265
  "bottom-end": "bottom-start"
24355
24266
  };
24356
24267
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
24357
- const triggerChild = React90__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
24358
- const triggerElement = React90__default.cloneElement(
24268
+ const triggerChild = React88__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
24269
+ const triggerElement = React88__default.cloneElement(
24359
24270
  triggerChild,
24360
24271
  {
24361
24272
  ref: triggerRef,
@@ -24450,14 +24361,14 @@ function useDataDnd(args) {
24450
24361
  const isZone = Boolean(dragGroup || accepts || sortable);
24451
24362
  const enabled = isZone || Boolean(dndRoot);
24452
24363
  const eventBus = useEventBus();
24453
- const parentRoot = React90__default.useContext(RootCtx);
24364
+ const parentRoot = React88__default.useContext(RootCtx);
24454
24365
  const isRoot = enabled && parentRoot === null;
24455
- const zoneId = React90__default.useId();
24366
+ const zoneId = React88__default.useId();
24456
24367
  const ownGroup = dragGroup ?? accepts ?? zoneId;
24457
- const [optimisticOrders, setOptimisticOrders] = React90__default.useState(() => /* @__PURE__ */ new Map());
24458
- const optimisticOrdersRef = React90__default.useRef(optimisticOrders);
24368
+ const [optimisticOrders, setOptimisticOrders] = React88__default.useState(() => /* @__PURE__ */ new Map());
24369
+ const optimisticOrdersRef = React88__default.useRef(optimisticOrders);
24459
24370
  optimisticOrdersRef.current = optimisticOrders;
24460
- const clearOptimisticOrder = React90__default.useCallback((group) => {
24371
+ const clearOptimisticOrder = React88__default.useCallback((group) => {
24461
24372
  setOptimisticOrders((prev) => {
24462
24373
  if (!prev.has(group)) return prev;
24463
24374
  const next = new Map(prev);
@@ -24482,7 +24393,7 @@ function useDataDnd(args) {
24482
24393
  const raw = it[dndItemIdField];
24483
24394
  return raw != null ? String(raw) : `__idx_${idx}`;
24484
24395
  }).join("|");
24485
- const itemIds = React90__default.useMemo(
24396
+ const itemIds = React88__default.useMemo(
24486
24397
  () => orderedItems.map((it, idx) => {
24487
24398
  const raw = it[dndItemIdField];
24488
24399
  return raw != null ? String(raw) : `__idx_${idx}`;
@@ -24493,7 +24404,7 @@ function useDataDnd(args) {
24493
24404
  const raw = it[dndItemIdField];
24494
24405
  return raw != null ? String(raw) : `__${idx}`;
24495
24406
  }).join("|");
24496
- React90__default.useEffect(() => {
24407
+ React88__default.useEffect(() => {
24497
24408
  const root = isRoot ? null : parentRoot;
24498
24409
  if (root) {
24499
24410
  root.clearOptimisticOrder(ownGroup);
@@ -24501,20 +24412,20 @@ function useDataDnd(args) {
24501
24412
  clearOptimisticOrder(ownGroup);
24502
24413
  }
24503
24414
  }, [itemsContentSig, ownGroup]);
24504
- const zonesRef = React90__default.useRef(/* @__PURE__ */ new Map());
24505
- const registerZone = React90__default.useCallback((zoneId2, meta2) => {
24415
+ const zonesRef = React88__default.useRef(/* @__PURE__ */ new Map());
24416
+ const registerZone = React88__default.useCallback((zoneId2, meta2) => {
24506
24417
  zonesRef.current.set(zoneId2, meta2);
24507
24418
  }, []);
24508
- const unregisterZone = React90__default.useCallback((zoneId2) => {
24419
+ const unregisterZone = React88__default.useCallback((zoneId2) => {
24509
24420
  zonesRef.current.delete(zoneId2);
24510
24421
  }, []);
24511
- const [activeDrag, setActiveDrag] = React90__default.useState(null);
24512
- const [overZoneGroup, setOverZoneGroup] = React90__default.useState(null);
24513
- const meta = React90__default.useMemo(
24422
+ const [activeDrag, setActiveDrag] = React88__default.useState(null);
24423
+ const [overZoneGroup, setOverZoneGroup] = React88__default.useState(null);
24424
+ const meta = React88__default.useMemo(
24514
24425
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
24515
24426
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
24516
24427
  );
24517
- React90__default.useEffect(() => {
24428
+ React88__default.useEffect(() => {
24518
24429
  const target = isRoot ? null : parentRoot;
24519
24430
  if (!target) {
24520
24431
  zonesRef.current.set(zoneId, meta);
@@ -24533,7 +24444,7 @@ function useDataDnd(args) {
24533
24444
  }, [parentRoot, isRoot, zoneId, meta]);
24534
24445
  const sensors = useAlmadarDndSensors(true);
24535
24446
  const collisionDetection = almadarDndCollisionDetection;
24536
- const findZoneByItem = React90__default.useCallback(
24447
+ const findZoneByItem = React88__default.useCallback(
24537
24448
  (id) => {
24538
24449
  for (const z of zonesRef.current.values()) {
24539
24450
  if (z.itemIds.includes(id)) return z;
@@ -24542,7 +24453,7 @@ function useDataDnd(args) {
24542
24453
  },
24543
24454
  []
24544
24455
  );
24545
- React90__default.useCallback(
24456
+ React88__default.useCallback(
24546
24457
  (group) => {
24547
24458
  for (const z of zonesRef.current.values()) {
24548
24459
  if (z.group === group) return z;
@@ -24551,7 +24462,7 @@ function useDataDnd(args) {
24551
24462
  },
24552
24463
  []
24553
24464
  );
24554
- const handleDragEnd = React90__default.useCallback(
24465
+ const handleDragEnd = React88__default.useCallback(
24555
24466
  (event) => {
24556
24467
  const { active, over } = event;
24557
24468
  const activeIdStr = String(active.id);
@@ -24642,8 +24553,8 @@ function useDataDnd(args) {
24642
24553
  },
24643
24554
  [eventBus]
24644
24555
  );
24645
- const sortableData = React90__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
24646
- const SortableItem = React90__default.useCallback(
24556
+ const sortableData = React88__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
24557
+ const SortableItem = React88__default.useCallback(
24647
24558
  ({ id, children }) => {
24648
24559
  const {
24649
24560
  attributes,
@@ -24683,7 +24594,7 @@ function useDataDnd(args) {
24683
24594
  id: droppableId,
24684
24595
  data: sortableData
24685
24596
  });
24686
- const ctx = React90__default.useContext(RootCtx);
24597
+ const ctx = React88__default.useContext(RootCtx);
24687
24598
  const activeDrag2 = ctx?.activeDrag ?? null;
24688
24599
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
24689
24600
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -24698,7 +24609,7 @@ function useDataDnd(args) {
24698
24609
  showForeignPlaceholder,
24699
24610
  ctxAvailable: ctx != null
24700
24611
  });
24701
- React90__default.useEffect(() => {
24612
+ React88__default.useEffect(() => {
24702
24613
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
24703
24614
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
24704
24615
  return /* @__PURE__ */ jsx(
@@ -24712,11 +24623,11 @@ function useDataDnd(args) {
24712
24623
  }
24713
24624
  );
24714
24625
  };
24715
- const rootContextValue = React90__default.useMemo(
24626
+ const rootContextValue = React88__default.useMemo(
24716
24627
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
24717
24628
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
24718
24629
  );
24719
- const handleDragStart = React90__default.useCallback((event) => {
24630
+ const handleDragStart = React88__default.useCallback((event) => {
24720
24631
  const sourceZone = findZoneByItem(event.active.id);
24721
24632
  const rect = event.active.rect.current.initial;
24722
24633
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -24735,7 +24646,7 @@ function useDataDnd(args) {
24735
24646
  isRoot
24736
24647
  });
24737
24648
  }, [findZoneByItem, isRoot, zoneId]);
24738
- const handleDragOver = React90__default.useCallback((event) => {
24649
+ const handleDragOver = React88__default.useCallback((event) => {
24739
24650
  const { active, over } = event;
24740
24651
  const overData = over?.data?.current;
24741
24652
  const overGroup = overData?.dndGroup ?? null;
@@ -24805,7 +24716,7 @@ function useDataDnd(args) {
24805
24716
  return next;
24806
24717
  });
24807
24718
  }, []);
24808
- const handleDragCancel = React90__default.useCallback((event) => {
24719
+ const handleDragCancel = React88__default.useCallback((event) => {
24809
24720
  setActiveDrag(null);
24810
24721
  setOverZoneGroup(null);
24811
24722
  dndLog.warn("dragCancel", {
@@ -24813,12 +24724,12 @@ function useDataDnd(args) {
24813
24724
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
24814
24725
  });
24815
24726
  }, []);
24816
- const handleDragEndWithCleanup = React90__default.useCallback((event) => {
24727
+ const handleDragEndWithCleanup = React88__default.useCallback((event) => {
24817
24728
  handleDragEnd(event);
24818
24729
  setActiveDrag(null);
24819
24730
  setOverZoneGroup(null);
24820
24731
  }, [handleDragEnd]);
24821
- const wrapContainer = React90__default.useCallback(
24732
+ const wrapContainer = React88__default.useCallback(
24822
24733
  (children) => {
24823
24734
  if (!enabled) return children;
24824
24735
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -24872,7 +24783,7 @@ var init_useDataDnd = __esm({
24872
24783
  init_useAlmadarDndCollision();
24873
24784
  init_Box();
24874
24785
  dndLog = createLogger("almadar:ui:dnd");
24875
- RootCtx = React90__default.createContext(null);
24786
+ RootCtx = React88__default.createContext(null);
24876
24787
  }
24877
24788
  });
24878
24789
  function renderIconInput(icon, props) {
@@ -25398,7 +25309,7 @@ function DataList({
25398
25309
  }) {
25399
25310
  const eventBus = useEventBus();
25400
25311
  const { t } = useTranslate();
25401
- const [visibleCount, setVisibleCount] = React90__default.useState(pageSize || Infinity);
25312
+ const [visibleCount, setVisibleCount] = React88__default.useState(pageSize || Infinity);
25402
25313
  const fieldDefs = fields ?? columns ?? [];
25403
25314
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
25404
25315
  const dnd = useDataDnd({
@@ -25417,7 +25328,7 @@ function DataList({
25417
25328
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
25418
25329
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
25419
25330
  const hasRenderProp = typeof children === "function";
25420
- React90__default.useEffect(() => {
25331
+ React88__default.useEffect(() => {
25421
25332
  const renderItemTypeOf = typeof schemaRenderItem;
25422
25333
  const childrenTypeOf = typeof children;
25423
25334
  if (data.length > 0 && !hasRenderProp) {
@@ -25521,7 +25432,7 @@ function DataList({
25521
25432
  const items2 = [...data];
25522
25433
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
25523
25434
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
25524
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
25435
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
25525
25436
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
25526
25437
  group.items.map((itemData, index) => {
25527
25438
  const id = itemData.id || `${gi}-${index}`;
@@ -25662,7 +25573,7 @@ function DataList({
25662
25573
  className
25663
25574
  ),
25664
25575
  children: [
25665
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
25576
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
25666
25577
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
25667
25578
  group.items.map(
25668
25579
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -26455,7 +26366,7 @@ var init_Flex = __esm({
26455
26366
  flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
26456
26367
  }
26457
26368
  }
26458
- return React90__default.createElement(Component2, {
26369
+ return React88__default.createElement(Component2, {
26459
26370
  className: cn(
26460
26371
  inline ? "inline-flex" : "flex",
26461
26372
  directionStyles[direction],
@@ -26574,7 +26485,7 @@ var init_Grid = __esm({
26574
26485
  as: Component2 = "div"
26575
26486
  }) => {
26576
26487
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
26577
- return React90__default.createElement(
26488
+ return React88__default.createElement(
26578
26489
  Component2,
26579
26490
  {
26580
26491
  className: cn(
@@ -26770,9 +26681,9 @@ var init_Popover = __esm({
26770
26681
  onMouseLeave: handleClose,
26771
26682
  onPointerDown: tapTriggerProps.onPointerDown
26772
26683
  };
26773
- const childElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
26684
+ const childElement = React88__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
26774
26685
  const childPointerDown = childElement.props.onPointerDown;
26775
- const triggerElement = React90__default.cloneElement(
26686
+ const triggerElement = React88__default.cloneElement(
26776
26687
  childElement,
26777
26688
  {
26778
26689
  ref: triggerRef,
@@ -27374,9 +27285,9 @@ var init_Tooltip = __esm({
27374
27285
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
27375
27286
  };
27376
27287
  }, []);
27377
- const triggerElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
27288
+ const triggerElement = React88__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
27378
27289
  const childPointerDown = triggerElement.props.onPointerDown;
27379
- const trigger = React90__default.cloneElement(triggerElement, {
27290
+ const trigger = React88__default.cloneElement(triggerElement, {
27380
27291
  ref: triggerRef,
27381
27292
  onMouseEnter: handleMouseEnter,
27382
27293
  onMouseLeave: handleMouseLeave,
@@ -27466,7 +27377,7 @@ var init_WizardProgress = __esm({
27466
27377
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
27467
27378
  const isActive = index === currentStep;
27468
27379
  const isCompleted = index < currentStep;
27469
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
27380
+ return /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
27470
27381
  /* @__PURE__ */ jsx(
27471
27382
  "button",
27472
27383
  {
@@ -28429,6 +28340,7 @@ var init_ProgressDots = __esm({
28429
28340
  });
28430
28341
  function StatBadge({
28431
28342
  assetUrl,
28343
+ iconUrl,
28432
28344
  label,
28433
28345
  value = 0,
28434
28346
  max,
@@ -28442,6 +28354,7 @@ function StatBadge({
28442
28354
  field: _field
28443
28355
  }) {
28444
28356
  const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
28357
+ const resolvedAsset = iconUrl ?? assetUrl;
28445
28358
  return /* @__PURE__ */ jsxs(
28446
28359
  "div",
28447
28360
  {
@@ -28452,10 +28365,10 @@ function StatBadge({
28452
28365
  className
28453
28366
  ),
28454
28367
  children: [
28455
- assetUrl ? /* @__PURE__ */ jsx(
28368
+ resolvedAsset ? /* @__PURE__ */ jsx(
28456
28369
  "img",
28457
28370
  {
28458
- src: assetUrl,
28371
+ src: resolvedAsset.url,
28459
28372
  alt: "",
28460
28373
  width: 16,
28461
28374
  height: 16,
@@ -28486,8 +28399,7 @@ function StatBadge({
28486
28399
  ScoreDisplay,
28487
28400
  {
28488
28401
  value: numValue,
28489
- size: size === "lg" ? "md" : "sm",
28490
- animated: true
28402
+ size: size === "lg" ? "md" : "sm"
28491
28403
  }
28492
28404
  ),
28493
28405
  format === "text" && /* @__PURE__ */ jsx("span", { className: "font-bold text-foreground", children: value })
@@ -28530,7 +28442,7 @@ function InventoryGrid({
28530
28442
  const eventBus = useEventBus();
28531
28443
  const slotCount = totalSlots ?? items.length;
28532
28444
  const emptySlotCount = Math.max(0, slotCount - items.length);
28533
- const handleSelect = React90.useCallback(
28445
+ const handleSelect = React88.useCallback(
28534
28446
  (id) => {
28535
28447
  onSelect?.(id);
28536
28448
  if (selectEvent) {
@@ -28637,12 +28549,14 @@ function QuestTracker({
28637
28549
  }
28638
28550
  ),
28639
28551
  /* @__PURE__ */ jsx(Box, { className: "mt-1.5", children: /* @__PURE__ */ jsx(
28640
- ProgressBar,
28552
+ HealthBar,
28641
28553
  {
28642
- value: quest.progress,
28554
+ current: quest.progress,
28643
28555
  max: quest.maxProgress,
28644
- variant: isCompleted ? "success" : isActive ? "primary" : "default",
28645
- size: "sm"
28556
+ format: "bar",
28557
+ size: "sm",
28558
+ animated: true,
28559
+ className: isCompleted ? "[--health-color:var(--color-success)]" : isActive ? "" : "opacity-60"
28646
28560
  }
28647
28561
  ) }),
28648
28562
  /* @__PURE__ */ jsxs(
@@ -28670,7 +28584,7 @@ var init_QuestTracker = __esm({
28670
28584
  "use client";
28671
28585
  init_cn();
28672
28586
  init_WaypointMarker();
28673
- init_ProgressBar();
28587
+ init_HealthBar();
28674
28588
  init_Typography();
28675
28589
  init_Box();
28676
28590
  init_Stack();
@@ -28761,35 +28675,35 @@ function GameCanvas2D({
28761
28675
  tickEvent,
28762
28676
  drawEvent,
28763
28677
  fps = 60,
28764
- backgroundImage = "",
28678
+ backgroundImage,
28765
28679
  assetBaseUrl,
28766
28680
  className
28767
28681
  }) {
28768
- const canvasRef = React90.useRef(null);
28769
- const rafRef = React90.useRef(0);
28770
- const frameRef = React90.useRef(0);
28771
- const lastTimeRef = React90.useRef(0);
28772
- const imageCache = React90.useRef(/* @__PURE__ */ new Map());
28682
+ const canvasRef = React88.useRef(null);
28683
+ const rafRef = React88.useRef(0);
28684
+ const frameRef = React88.useRef(0);
28685
+ const lastTimeRef = React88.useRef(0);
28686
+ const imageCache = React88.useRef(/* @__PURE__ */ new Map());
28773
28687
  const emit = useEmitEvent();
28774
- const onDrawRef = React90.useRef(onDraw);
28688
+ const onDrawRef = React88.useRef(onDraw);
28775
28689
  onDrawRef.current = onDraw;
28776
- const onTickRef = React90.useRef(onTick);
28690
+ const onTickRef = React88.useRef(onTick);
28777
28691
  onTickRef.current = onTick;
28778
- const tickEventRef = React90.useRef(tickEvent);
28692
+ const tickEventRef = React88.useRef(tickEvent);
28779
28693
  tickEventRef.current = tickEvent;
28780
- const drawEventRef = React90.useRef(drawEvent);
28694
+ const drawEventRef = React88.useRef(drawEvent);
28781
28695
  drawEventRef.current = drawEvent;
28782
- const emitRef = React90.useRef(emit);
28696
+ const emitRef = React88.useRef(emit);
28783
28697
  emitRef.current = emit;
28784
- const assetBaseUrlRef = React90.useRef(assetBaseUrl);
28698
+ const assetBaseUrlRef = React88.useRef(assetBaseUrl);
28785
28699
  assetBaseUrlRef.current = assetBaseUrl;
28786
- const backgroundImageRef = React90.useRef(backgroundImage);
28700
+ const backgroundImageRef = React88.useRef(backgroundImage);
28787
28701
  backgroundImageRef.current = backgroundImage;
28788
- const widthRef = React90.useRef(width);
28702
+ const widthRef = React88.useRef(width);
28789
28703
  widthRef.current = width;
28790
- const heightRef = React90.useRef(height);
28704
+ const heightRef = React88.useRef(height);
28791
28705
  heightRef.current = height;
28792
- const loadImage = React90.useCallback((url) => {
28706
+ const loadImage = React88.useCallback((url) => {
28793
28707
  const base = assetBaseUrlRef.current;
28794
28708
  if (!url.startsWith("http") && !base) return null;
28795
28709
  const fullUrl = url.startsWith("http") ? url : `${base}${url}`;
@@ -28803,7 +28717,7 @@ function GameCanvas2D({
28803
28717
  }
28804
28718
  return null;
28805
28719
  }, []);
28806
- React90.useEffect(() => {
28720
+ React88.useEffect(() => {
28807
28721
  const canvas = canvasRef.current;
28808
28722
  if (!canvas) return;
28809
28723
  const ctx = canvas.getContext("2d");
@@ -28825,7 +28739,7 @@ function GameCanvas2D({
28825
28739
  emitRef.current(tickEventRef.current, { dt, frame });
28826
28740
  }
28827
28741
  if (backgroundImageRef.current) {
28828
- const bgImg = loadImage(backgroundImageRef.current);
28742
+ const bgImg = loadImage(backgroundImageRef.current.url);
28829
28743
  if (bgImg) {
28830
28744
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
28831
28745
  } else {
@@ -28951,26 +28865,14 @@ function HealthPanel({
28951
28865
  )
28952
28866
  }
28953
28867
  ),
28954
- effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxs(
28955
- Badge,
28868
+ effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsx(
28869
+ StatusEffect,
28956
28870
  {
28871
+ assetUrl: effect.assetUrl,
28872
+ icon: effect.icon,
28873
+ label: effect.label,
28957
28874
  variant: effectVariantMap[effect.variant ?? "neutral"],
28958
- size: "sm",
28959
- icon: effect.assetUrl ? void 0 : effect.icon,
28960
- children: [
28961
- effect.assetUrl && /* @__PURE__ */ jsx(
28962
- "img",
28963
- {
28964
- src: effect.assetUrl,
28965
- alt: "",
28966
- width: 12,
28967
- height: 12,
28968
- style: { imageRendering: "pixelated", objectFit: "contain" },
28969
- className: "flex-shrink-0 inline-block"
28970
- }
28971
- ),
28972
- effect.label
28973
- ]
28875
+ size: "sm"
28974
28876
  },
28975
28877
  i
28976
28878
  )) })
@@ -28984,17 +28886,17 @@ var init_HealthPanel = __esm({
28984
28886
  "use client";
28985
28887
  init_cn();
28986
28888
  init_HealthBar();
28889
+ init_StatusEffect();
28987
28890
  init_Box();
28988
28891
  init_Typography();
28989
- init_Badge();
28990
28892
  sizeMap18 = {
28991
28893
  sm: { gap: "gap-1", padding: "px-2 py-1.5", text: "text-xs", barSize: "sm" },
28992
28894
  md: { gap: "gap-1.5", padding: "px-3 py-2", text: "text-sm", barSize: "md" },
28993
28895
  lg: { gap: "gap-2", padding: "px-4 py-3", text: "text-base", barSize: "lg" }
28994
28896
  };
28995
28897
  effectVariantMap = {
28996
- buff: "success",
28997
- debuff: "danger",
28898
+ buff: "buff",
28899
+ debuff: "debuff",
28998
28900
  neutral: "neutral"
28999
28901
  };
29000
28902
  HealthPanel.displayName = "HealthPanel";
@@ -29014,13 +28916,13 @@ function ScoreBoard({
29014
28916
  const multiplier = rawMultiplier ?? 1;
29015
28917
  const level = rawLevel ?? 1;
29016
28918
  return /* @__PURE__ */ jsx(
29017
- Card,
28919
+ Box,
29018
28920
  {
29019
28921
  className: cn(
29020
- "bg-[var(--color-card)]/90 border-border backdrop-blur-sm",
28922
+ "rounded-container border border-border bg-[var(--color-card)]/90 backdrop-blur-sm p-3",
29021
28923
  className
29022
28924
  ),
29023
- children: /* @__PURE__ */ jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-wrap", children: [
28925
+ children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-wrap", children: [
29024
28926
  /* @__PURE__ */ jsx(
29025
28927
  StatBadge,
29026
28928
  {
@@ -29062,7 +28964,7 @@ function ScoreBoard({
29062
28964
  }
29063
28965
  ),
29064
28966
  combo != null && combo > 0 && /* @__PURE__ */ jsx(ComboCounter, { combo, multiplier, size: "sm" })
29065
- ] }) })
28967
+ ] })
29066
28968
  }
29067
28969
  );
29068
28970
  }
@@ -29072,7 +28974,6 @@ var init_ScoreBoard = __esm({
29072
28974
  init_cn();
29073
28975
  init_ComboCounter();
29074
28976
  init_StatBadge();
29075
- init_Card();
29076
28977
  init_Box();
29077
28978
  ScoreBoard.displayName = "ScoreBoard";
29078
28979
  }
@@ -29128,7 +29029,7 @@ function TurnPanel({
29128
29029
  className
29129
29030
  }) {
29130
29031
  const eventBus = useEventBus();
29131
- const handleAction = React90.useCallback(
29032
+ const handleAction = React88.useCallback(
29132
29033
  (event) => {
29133
29034
  if (event) {
29134
29035
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -29153,28 +29054,16 @@ function TurnPanel({
29153
29054
  activeTeam
29154
29055
  }
29155
29056
  ),
29156
- actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsxs(
29157
- Button,
29057
+ actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsx(
29058
+ ActionButton,
29158
29059
  {
29159
- variant: "ghost",
29160
- size: "sm",
29060
+ label: action.label,
29061
+ icon: action.assetUrl ? void 0 : action.icon,
29062
+ assetUrl: action.assetUrl,
29161
29063
  disabled: action.disabled,
29162
- leftIcon: action.assetUrl ? void 0 : action.icon,
29163
- onClick: () => handleAction(action.event),
29164
- children: [
29165
- action.assetUrl && /* @__PURE__ */ jsx(
29166
- "img",
29167
- {
29168
- src: action.assetUrl,
29169
- alt: "",
29170
- width: 14,
29171
- height: 14,
29172
- style: { imageRendering: "pixelated", objectFit: "contain" },
29173
- className: "flex-shrink-0"
29174
- }
29175
- ),
29176
- action.label
29177
- ]
29064
+ variant: "secondary",
29065
+ size: "sm",
29066
+ onClick: () => handleAction(action.event)
29178
29067
  },
29179
29068
  i
29180
29069
  )) })
@@ -29188,7 +29077,7 @@ var init_TurnPanel = __esm({
29188
29077
  "use client";
29189
29078
  init_cn();
29190
29079
  init_TurnIndicator();
29191
- init_Button();
29080
+ init_ActionButton();
29192
29081
  init_Box();
29193
29082
  init_useEventBus();
29194
29083
  DEFAULT_TURN_ACTIONS = [
@@ -29221,7 +29110,7 @@ function EnemyPlate({
29221
29110
  assetUrl && /* @__PURE__ */ jsx(
29222
29111
  "img",
29223
29112
  {
29224
- src: assetUrl,
29113
+ src: assetUrl.url,
29225
29114
  alt: name,
29226
29115
  width: 24,
29227
29116
  height: 24,
@@ -29239,7 +29128,7 @@ function EnemyPlate({
29239
29128
  }
29240
29129
  )
29241
29130
  ] }),
29242
- level != null && /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
29131
+ level != null && /* @__PURE__ */ jsxs("span", { className: "text-xs font-bold text-muted-foreground bg-muted/60 rounded px-1.5 py-0.5 border border-border/50 shrink-0", children: [
29243
29132
  "Lv.",
29244
29133
  level
29245
29134
  ] })
@@ -29270,12 +29159,12 @@ function EnemyPlate({
29270
29159
  )
29271
29160
  ] }),
29272
29161
  effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsx(
29273
- Badge,
29162
+ StatusEffect,
29274
29163
  {
29275
- variant: effectVariantMap2[effect.variant ?? "neutral"],
29276
- size: "sm",
29277
29164
  icon: effect.icon,
29278
- children: effect.label
29165
+ label: effect.label,
29166
+ variant: effectVariantMap2[effect.variant ?? "neutral"],
29167
+ size: "sm"
29279
29168
  },
29280
29169
  i
29281
29170
  )) })
@@ -29289,12 +29178,12 @@ var init_EnemyPlate = __esm({
29289
29178
  "use client";
29290
29179
  init_cn();
29291
29180
  init_HealthBar();
29181
+ init_StatusEffect();
29292
29182
  init_Box();
29293
29183
  init_Typography();
29294
- init_Badge();
29295
29184
  effectVariantMap2 = {
29296
- buff: "success",
29297
- debuff: "danger",
29185
+ buff: "buff",
29186
+ debuff: "debuff",
29298
29187
  neutral: "neutral"
29299
29188
  };
29300
29189
  DEFAULT_ENEMY_EFFECTS = [
@@ -29309,7 +29198,7 @@ function UnitCommandBar({
29309
29198
  className
29310
29199
  }) {
29311
29200
  const eventBus = useEventBus();
29312
- const handleCommand = React90.useCallback(
29201
+ const handleCommand = React88.useCallback(
29313
29202
  (event) => {
29314
29203
  if (event) {
29315
29204
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -29324,27 +29213,18 @@ function UnitCommandBar({
29324
29213
  "flex items-center gap-1.5 rounded-container bg-[var(--color-card)]/90 border border-border backdrop-blur-sm px-2 py-1.5",
29325
29214
  className
29326
29215
  ),
29327
- children: commands.map((command, i) => /* @__PURE__ */ jsxs(Box, { className: "flex flex-col items-center gap-0.5", children: [
29328
- /* @__PURE__ */ jsx(
29329
- Button,
29330
- {
29331
- variant: "ghost",
29332
- size: "sm",
29333
- disabled: command.disabled,
29334
- leftIcon: command.icon,
29335
- onClick: () => handleCommand(command.event),
29336
- children: command.label
29337
- }
29338
- ),
29339
- command.hotkey && /* @__PURE__ */ jsx(
29340
- Typography,
29341
- {
29342
- variant: "caption",
29343
- className: "text-muted-foreground text-xs font-mono",
29344
- children: command.hotkey
29345
- }
29346
- )
29347
- ] }, i))
29216
+ children: commands.map((command, i) => /* @__PURE__ */ jsx(Box, { className: "flex flex-col items-center gap-0.5", children: /* @__PURE__ */ jsx(
29217
+ ActionButton,
29218
+ {
29219
+ label: command.label,
29220
+ icon: command.icon,
29221
+ disabled: command.disabled,
29222
+ hotkey: command.hotkey,
29223
+ variant: "secondary",
29224
+ size: "sm",
29225
+ onClick: () => handleCommand(command.event)
29226
+ }
29227
+ ) }, i))
29348
29228
  }
29349
29229
  );
29350
29230
  }
@@ -29353,9 +29233,8 @@ var init_UnitCommandBar = __esm({
29353
29233
  "components/game/molecules/UnitCommandBar.tsx"() {
29354
29234
  "use client";
29355
29235
  init_cn();
29356
- init_Button();
29236
+ init_ActionButton();
29357
29237
  init_Box();
29358
- init_Typography();
29359
29238
  init_useEventBus();
29360
29239
  DEFAULT_COMMANDS = [
29361
29240
  { label: "Move", icon: "move", event: "MOVE", hotkey: "M" },
@@ -29573,7 +29452,7 @@ function DialogueBox({
29573
29452
  "div",
29574
29453
  {
29575
29454
  className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
29576
- style: { backgroundImage: `url(${backgroundImage})` },
29455
+ style: { backgroundImage: `url(${backgroundImage?.url})` },
29577
29456
  "aria-hidden": "true"
29578
29457
  }
29579
29458
  ),
@@ -29588,7 +29467,7 @@ function DialogueBox({
29588
29467
  children: /* @__PURE__ */ jsx(
29589
29468
  "img",
29590
29469
  {
29591
- src: portraitUrl,
29470
+ src: portraitUrl?.url,
29592
29471
  alt: dialogue.speaker,
29593
29472
  className: "h-full w-auto object-contain drop-shadow-2xl"
29594
29473
  }
@@ -29860,7 +29739,7 @@ function GameMenu({
29860
29739
  } catch {
29861
29740
  }
29862
29741
  const eventBus = eventBusProp || eventBusFromHook;
29863
- const handleOptionClick = React90.useCallback(
29742
+ const handleOptionClick = React88.useCallback(
29864
29743
  (option) => {
29865
29744
  if (option.event && eventBus) {
29866
29745
  eventBus.emit(`UI:${option.event}`, { option });
@@ -29979,7 +29858,7 @@ function GameOverScreen({
29979
29858
  } catch {
29980
29859
  }
29981
29860
  const eventBus = eventBusProp || eventBusFromHook;
29982
- const handleActionClick = React90.useCallback(
29861
+ const handleActionClick = React88.useCallback(
29983
29862
  (action) => {
29984
29863
  if (action.event && eventBus) {
29985
29864
  eventBus.emit(`UI:${action.event}`, { action });
@@ -30194,6 +30073,7 @@ function PlatformerCanvas({
30194
30073
  rightEvent = "MOVE_RIGHT",
30195
30074
  jumpEvent = "JUMP",
30196
30075
  stopEvent = "STOP",
30076
+ effects = [],
30197
30077
  className
30198
30078
  }) {
30199
30079
  const canvasRef = useRef(null);
@@ -30264,7 +30144,8 @@ function PlatformerCanvas({
30264
30144
  playerSprite,
30265
30145
  tileSprites,
30266
30146
  backgroundImage,
30267
- assetBaseUrl
30147
+ assetBaseUrl,
30148
+ effects
30268
30149
  });
30269
30150
  propsRef.current = {
30270
30151
  platforms,
@@ -30277,7 +30158,8 @@ function PlatformerCanvas({
30277
30158
  playerSprite,
30278
30159
  tileSprites,
30279
30160
  backgroundImage,
30280
- assetBaseUrl
30161
+ assetBaseUrl,
30162
+ effects
30281
30163
  };
30282
30164
  const handleKeyDown = useCallback((e) => {
30283
30165
  if (keysRef.current.has(e.code)) return;
@@ -30344,7 +30226,8 @@ function PlatformerCanvas({
30344
30226
  bgColor: bg,
30345
30227
  playerSprite: pSprite,
30346
30228
  tileSprites: tSprites,
30347
- backgroundImage: bgImg
30229
+ backgroundImage: bgImg,
30230
+ effects: fxList
30348
30231
  } = propsRef.current;
30349
30232
  const auth = playerRef.current;
30350
30233
  const interped = positions.get("player");
@@ -30498,6 +30381,18 @@ function PlatformerCanvas({
30498
30381
  ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
30499
30382
  ctx.fill();
30500
30383
  }
30384
+ for (const fx of fxList) {
30385
+ const fxScreenX = fx.x - camX;
30386
+ const fxScreenY = fx.y - camY;
30387
+ const alpha = Math.min(1, fx.ttl / 4);
30388
+ const prev = ctx.globalAlpha;
30389
+ ctx.globalAlpha = alpha;
30390
+ ctx.fillStyle = "#ffe066";
30391
+ ctx.beginPath();
30392
+ ctx.arc(fxScreenX, fxScreenY, 12, 0, Math.PI * 2);
30393
+ ctx.fill();
30394
+ ctx.globalAlpha = prev;
30395
+ }
30501
30396
  };
30502
30397
  return interp.startLoop(drawFrame);
30503
30398
  }, [interp.startLoop, loadImage]);
@@ -30911,13 +30806,13 @@ var init_MapView = __esm({
30911
30806
  shadowSize: [41, 41]
30912
30807
  });
30913
30808
  L.Marker.prototype.options.icon = defaultIcon;
30914
- const { useEffect: useEffect83, useRef: useRef80, useCallback: useCallback126, useState: useState113 } = React90__default;
30809
+ const { useEffect: useEffect81, useRef: useRef80, useCallback: useCallback126, useState: useState111 } = React88__default;
30915
30810
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
30916
30811
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
30917
30812
  function MapUpdater({ centerLat, centerLng, zoom }) {
30918
30813
  const map = useMap();
30919
30814
  const prevRef = useRef80({ centerLat, centerLng, zoom });
30920
- useEffect83(() => {
30815
+ useEffect81(() => {
30921
30816
  const prev = prevRef.current;
30922
30817
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
30923
30818
  map.setView([centerLat, centerLng], zoom);
@@ -30928,7 +30823,7 @@ var init_MapView = __esm({
30928
30823
  }
30929
30824
  function MapClickHandler({ onMapClick }) {
30930
30825
  const map = useMap();
30931
- useEffect83(() => {
30826
+ useEffect81(() => {
30932
30827
  if (!onMapClick) return;
30933
30828
  const handler = (e) => {
30934
30829
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -30956,7 +30851,7 @@ var init_MapView = __esm({
30956
30851
  showAttribution = true
30957
30852
  }) {
30958
30853
  const eventBus = useEventBus3();
30959
- const [clickedPosition, setClickedPosition] = useState113(null);
30854
+ const [clickedPosition, setClickedPosition] = useState111(null);
30960
30855
  const handleMapClick = useCallback126((lat, lng) => {
30961
30856
  if (showClickedPin) {
30962
30857
  setClickedPosition({ lat, lng });
@@ -31826,8 +31721,8 @@ function TableView({
31826
31721
  }) {
31827
31722
  const eventBus = useEventBus();
31828
31723
  const { t } = useTranslate();
31829
- const [visibleCount, setVisibleCount] = React90__default.useState(pageSize > 0 ? pageSize : Infinity);
31830
- const [localSelected, setLocalSelected] = React90__default.useState(/* @__PURE__ */ new Set());
31724
+ const [visibleCount, setVisibleCount] = React88__default.useState(pageSize > 0 ? pageSize : Infinity);
31725
+ const [localSelected, setLocalSelected] = React88__default.useState(/* @__PURE__ */ new Set());
31831
31726
  const colDefs = columns ?? fields ?? [];
31832
31727
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
31833
31728
  const dnd = useDataDnd({
@@ -32022,12 +31917,12 @@ function TableView({
32022
31917
  ]
32023
31918
  }
32024
31919
  );
32025
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React90__default.Fragment, { children: rowInner }, id);
31920
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React88__default.Fragment, { children: rowInner }, id);
32026
31921
  };
32027
31922
  const items = Array.from(data);
32028
31923
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
32029
31924
  let runningIndex = 0;
32030
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
31925
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
32031
31926
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
32032
31927
  group.items.map((row) => renderRow(row, runningIndex++))
32033
31928
  ] }, gi)) });
@@ -33384,7 +33279,7 @@ var init_StepFlow = __esm({
33384
33279
  className
33385
33280
  }) => {
33386
33281
  if (orientation === "vertical") {
33387
- 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: [
33282
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React88__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
33388
33283
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
33389
33284
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
33390
33285
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -33395,7 +33290,7 @@ var init_StepFlow = __esm({
33395
33290
  ] })
33396
33291
  ] }) }, index)) });
33397
33292
  }
33398
- 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: [
33293
+ 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(React88__default.Fragment, { children: [
33399
33294
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
33400
33295
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
33401
33296
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -34380,7 +34275,7 @@ var init_LikertScale = __esm({
34380
34275
  md: "text-base",
34381
34276
  lg: "text-lg"
34382
34277
  };
34383
- LikertScale = React90__default.forwardRef(
34278
+ LikertScale = React88__default.forwardRef(
34384
34279
  ({
34385
34280
  question,
34386
34281
  options = DEFAULT_LIKERT_OPTIONS,
@@ -34392,7 +34287,7 @@ var init_LikertScale = __esm({
34392
34287
  variant = "radios",
34393
34288
  className
34394
34289
  }, ref) => {
34395
- const groupId = React90__default.useId();
34290
+ const groupId = React88__default.useId();
34396
34291
  const eventBus = useEventBus();
34397
34292
  const handleSelect = useCallback(
34398
34293
  (next) => {
@@ -36674,7 +36569,7 @@ var init_DocBreadcrumb = __esm({
36674
36569
  "aria-label": t("aria.breadcrumb"),
36675
36570
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
36676
36571
  const isLast = idx === items.length - 1;
36677
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
36572
+ return /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
36678
36573
  idx > 0 && /* @__PURE__ */ jsx(
36679
36574
  Icon,
36680
36575
  {
@@ -37543,7 +37438,7 @@ var init_MiniStateMachine = __esm({
37543
37438
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
37544
37439
  const tc = transitionCounts[s.name] ?? 0;
37545
37440
  const role = getStateRole(s.name, s.isInitial ?? void 0, s.isTerminal ?? void 0, tc, maxTC);
37546
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
37441
+ return /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
37547
37442
  /* @__PURE__ */ jsx(
37548
37443
  AvlState,
37549
37444
  {
@@ -37747,7 +37642,7 @@ var init_PageHeader = __esm({
37747
37642
  info: "bg-info/10 text-info"
37748
37643
  };
37749
37644
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
37750
- 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: [
37645
+ 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(React88__default.Fragment, { children: [
37751
37646
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
37752
37647
  crumb.href ? /* @__PURE__ */ jsx(
37753
37648
  "a",
@@ -38105,7 +38000,7 @@ var init_Section = __esm({
38105
38000
  as: Component2 = "section"
38106
38001
  }) => {
38107
38002
  const hasHeader = title || description || action;
38108
- return React90__default.createElement(
38003
+ return React88__default.createElement(
38109
38004
  Component2,
38110
38005
  {
38111
38006
  className: cn(
@@ -38473,7 +38368,7 @@ var init_WizardContainer = __esm({
38473
38368
  const isCompleted = index < currentStep;
38474
38369
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
38475
38370
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
38476
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
38371
+ return /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
38477
38372
  /* @__PURE__ */ jsx(
38478
38373
  Button,
38479
38374
  {
@@ -41052,7 +40947,7 @@ var init_DetailPanel = __esm({
41052
40947
  }
41053
40948
  });
41054
40949
  function extractTitle(children) {
41055
- if (!React90__default.isValidElement(children)) return void 0;
40950
+ if (!React88__default.isValidElement(children)) return void 0;
41056
40951
  const props = children.props;
41057
40952
  if (typeof props.title === "string") {
41058
40953
  return props.title;
@@ -41107,7 +41002,7 @@ function LinearView({
41107
41002
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
41108
41003
  const isDone = i < currentIdx;
41109
41004
  const isCurrent = i === currentIdx;
41110
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
41005
+ return /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
41111
41006
  i > 0 && /* @__PURE__ */ jsx(
41112
41007
  Typography,
41113
41008
  {
@@ -41878,7 +41773,6 @@ var init_FeatureGridOrganism = __esm({
41878
41773
  });
41879
41774
  function FishingBoard({
41880
41775
  backgroundImage,
41881
- assetBaseUrl,
41882
41776
  scale = 1,
41883
41777
  showMinimap = false,
41884
41778
  enableCamera = true,
@@ -41896,8 +41790,7 @@ function FishingBoard({
41896
41790
  {
41897
41791
  width,
41898
41792
  height,
41899
- backgroundImage: backgroundImage ?? "",
41900
- assetBaseUrl,
41793
+ backgroundImage,
41901
41794
  fps: 60,
41902
41795
  className: "w-full h-full"
41903
41796
  }
@@ -42093,12 +41986,12 @@ var init_Form = __esm({
42093
41986
  const isSchemaEntity = isOrbitalEntitySchema(entity);
42094
41987
  const resolvedEntity = isSchemaEntity ? entity : void 0;
42095
41988
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
42096
- const normalizedInitialData = React90__default.useMemo(() => {
41989
+ const normalizedInitialData = React88__default.useMemo(() => {
42097
41990
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
42098
41991
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
42099
41992
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
42100
41993
  }, [entity, initialData]);
42101
- const entityDerivedFields = React90__default.useMemo(() => {
41994
+ const entityDerivedFields = React88__default.useMemo(() => {
42102
41995
  if (fields && fields.length > 0) return void 0;
42103
41996
  if (!resolvedEntity) return void 0;
42104
41997
  return resolvedEntity.fields.map(
@@ -42119,16 +42012,16 @@ var init_Form = __esm({
42119
42012
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
42120
42013
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
42121
42014
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
42122
- const [formData, setFormData] = React90__default.useState(
42015
+ const [formData, setFormData] = React88__default.useState(
42123
42016
  normalizedInitialData
42124
42017
  );
42125
- const [collapsedSections, setCollapsedSections] = React90__default.useState(
42018
+ const [collapsedSections, setCollapsedSections] = React88__default.useState(
42126
42019
  /* @__PURE__ */ new Set()
42127
42020
  );
42128
- const [submitError, setSubmitError] = React90__default.useState(null);
42129
- const formRef = React90__default.useRef(null);
42021
+ const [submitError, setSubmitError] = React88__default.useState(null);
42022
+ const formRef = React88__default.useRef(null);
42130
42023
  const formMode = props.mode;
42131
- const mountedRef = React90__default.useRef(false);
42024
+ const mountedRef = React88__default.useRef(false);
42132
42025
  if (!mountedRef.current) {
42133
42026
  mountedRef.current = true;
42134
42027
  debug("forms", "mount", {
@@ -42141,7 +42034,7 @@ var init_Form = __esm({
42141
42034
  });
42142
42035
  }
42143
42036
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
42144
- const evalContext = React90__default.useMemo(
42037
+ const evalContext = React88__default.useMemo(
42145
42038
  () => ({
42146
42039
  formValues: formData,
42147
42040
  globalVariables: externalContext?.globalVariables ?? {},
@@ -42150,7 +42043,7 @@ var init_Form = __esm({
42150
42043
  }),
42151
42044
  [formData, externalContext]
42152
42045
  );
42153
- React90__default.useEffect(() => {
42046
+ React88__default.useEffect(() => {
42154
42047
  debug("forms", "initialData-sync", {
42155
42048
  mode: formMode,
42156
42049
  normalizedInitialData,
@@ -42161,7 +42054,7 @@ var init_Form = __esm({
42161
42054
  setFormData(normalizedInitialData);
42162
42055
  }
42163
42056
  }, [normalizedInitialData]);
42164
- const processCalculations = React90__default.useCallback(
42057
+ const processCalculations = React88__default.useCallback(
42165
42058
  (changedFieldId, newFormData) => {
42166
42059
  if (!hiddenCalculations.length) return;
42167
42060
  const context = {
@@ -42186,7 +42079,7 @@ var init_Form = __esm({
42186
42079
  },
42187
42080
  [hiddenCalculations, externalContext, eventBus]
42188
42081
  );
42189
- const checkViolations = React90__default.useCallback(
42082
+ const checkViolations = React88__default.useCallback(
42190
42083
  (changedFieldId, newFormData) => {
42191
42084
  if (!violationTriggers.length) return;
42192
42085
  const context = {
@@ -42224,7 +42117,7 @@ var init_Form = __esm({
42224
42117
  processCalculations(name, newFormData);
42225
42118
  checkViolations(name, newFormData);
42226
42119
  };
42227
- const isFieldVisible = React90__default.useCallback(
42120
+ const isFieldVisible = React88__default.useCallback(
42228
42121
  (fieldName) => {
42229
42122
  const condition = conditionalFields[fieldName];
42230
42123
  if (!condition) return true;
@@ -42232,7 +42125,7 @@ var init_Form = __esm({
42232
42125
  },
42233
42126
  [conditionalFields, evalContext]
42234
42127
  );
42235
- const isSectionVisible = React90__default.useCallback(
42128
+ const isSectionVisible = React88__default.useCallback(
42236
42129
  (section) => {
42237
42130
  if (!section.condition) return true;
42238
42131
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -42308,7 +42201,7 @@ var init_Form = __esm({
42308
42201
  eventBus.emit(`UI:${onCancel}`);
42309
42202
  }
42310
42203
  };
42311
- const renderField = React90__default.useCallback(
42204
+ const renderField = React88__default.useCallback(
42312
42205
  (field) => {
42313
42206
  const fieldName = field.name || field.field;
42314
42207
  if (!fieldName) return null;
@@ -42329,7 +42222,7 @@ var init_Form = __esm({
42329
42222
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
42330
42223
  );
42331
42224
  const effectiveFields = entityDerivedFields ?? fields;
42332
- const normalizedFields = React90__default.useMemo(() => {
42225
+ const normalizedFields = React88__default.useMemo(() => {
42333
42226
  if (!effectiveFields || effectiveFields.length === 0) return [];
42334
42227
  return effectiveFields.map((field) => {
42335
42228
  if (typeof field === "string") {
@@ -42353,7 +42246,7 @@ var init_Form = __esm({
42353
42246
  return field;
42354
42247
  });
42355
42248
  }, [effectiveFields, resolvedEntity]);
42356
- const schemaFields = React90__default.useMemo(() => {
42249
+ const schemaFields = React88__default.useMemo(() => {
42357
42250
  if (normalizedFields.length === 0) return null;
42358
42251
  if (isDebugEnabled()) {
42359
42252
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -42363,7 +42256,7 @@ var init_Form = __esm({
42363
42256
  }
42364
42257
  return normalizedFields.map(renderField).filter(Boolean);
42365
42258
  }, [normalizedFields, renderField, entityName, conditionalFields]);
42366
- const sectionElements = React90__default.useMemo(() => {
42259
+ const sectionElements = React88__default.useMemo(() => {
42367
42260
  if (!sections || sections.length === 0) return null;
42368
42261
  return sections.map((section) => {
42369
42262
  if (!isSectionVisible(section)) {
@@ -43884,7 +43777,6 @@ var init_GameCanvas3D2 = __esm({
43884
43777
  className,
43885
43778
  isLoading: externalLoading,
43886
43779
  error: externalError,
43887
- entity,
43888
43780
  preloadAssets = [],
43889
43781
  tileClickEvent,
43890
43782
  unitClickEvent,
@@ -44117,7 +44009,7 @@ var init_GameCanvas3D2 = __esm({
44117
44009
  children: /* @__PURE__ */ jsx(
44118
44010
  ModelLoader,
44119
44011
  {
44120
- url: tile.modelUrl,
44012
+ url: tile.modelUrl.url,
44121
44013
  scale: 0.95,
44122
44014
  fallbackGeometry: "box",
44123
44015
  castShadow: true,
@@ -44182,7 +44074,7 @@ var init_GameCanvas3D2 = __esm({
44182
44074
  /* @__PURE__ */ jsx(
44183
44075
  ModelLoader,
44184
44076
  {
44185
- url: unit.modelUrl,
44077
+ url: unit.modelUrl.url,
44186
44078
  scale: modelScale,
44187
44079
  fallbackGeometry: "box",
44188
44080
  castShadow: true
@@ -44242,7 +44134,7 @@ var init_GameCanvas3D2 = __esm({
44242
44134
  return /* @__PURE__ */ jsx(
44243
44135
  ModelLoader,
44244
44136
  {
44245
- url: feature.assetUrl,
44137
+ url: feature.assetUrl.url,
44246
44138
  position,
44247
44139
  scale: 0.5,
44248
44140
  rotation: [0, feature.rotation ?? 0, 0],
@@ -44463,7 +44355,18 @@ function GameBoard3D({
44463
44355
  const row = boardEntity(entity);
44464
44356
  const eventBus = useEventBus();
44465
44357
  const entityUnits = row ? rows(row.units) : [];
44466
- const units = entityUnits;
44358
+ const units = entityUnits.map((r) => ({
44359
+ id: str(r.id),
44360
+ x: num(r.x),
44361
+ y: num(r.y),
44362
+ z: num(r.z),
44363
+ faction: str(r.faction) || "neutral",
44364
+ team: str(r.team) || str(r.faction) || "neutral",
44365
+ unitType: r.unitType == null ? void 0 : str(r.unitType),
44366
+ name: r.name == null ? void 0 : str(r.name),
44367
+ health: r.health == null ? void 0 : num(r.health),
44368
+ maxHealth: r.maxHealth == null ? void 0 : num(r.maxHealth)
44369
+ }));
44467
44370
  const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
44468
44371
  const phase = row ? str(row.phase) : "observation";
44469
44372
  const result = row ? str(row.result) : "none";
@@ -44620,7 +44523,7 @@ var init_GameBoard3D = __esm({
44620
44523
  }
44621
44524
  });
44622
44525
  function asDescriptor(v) {
44623
- if (Array.isArray(v) || React90__default.isValidElement(v)) return null;
44526
+ if (Array.isArray(v) || React88__default.isValidElement(v)) return null;
44624
44527
  const o = v;
44625
44528
  if (typeof o.type !== "string") return null;
44626
44529
  const props = o.props !== void 0 && typeof o.props === "object" && !Array.isArray(o.props) && o.props !== null ? o.props : void 0;
@@ -44635,10 +44538,10 @@ function getSlotContentRenderer2() {
44635
44538
  }
44636
44539
  function resolveDescriptor(value, idPrefix) {
44637
44540
  if (value === null || value === void 0) return value;
44638
- if (React90__default.isValidElement(value)) return value;
44541
+ if (React88__default.isValidElement(value)) return value;
44639
44542
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
44640
44543
  if (Array.isArray(value)) {
44641
- return value.map((item, i) => /* @__PURE__ */ jsx(React90__default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
44544
+ return value.map((item, i) => /* @__PURE__ */ jsx(React88__default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
44642
44545
  }
44643
44546
  if (typeof value === "object" && value !== null) {
44644
44547
  const desc = asDescriptor(value);
@@ -44738,10 +44641,10 @@ function getSlotContentRenderer3() {
44738
44641
  }
44739
44642
  function resolveDescriptor2(value, idPrefix) {
44740
44643
  if (value === null || value === void 0) return value;
44741
- if (React90__default.isValidElement(value)) return value;
44644
+ if (React88__default.isValidElement(value)) return value;
44742
44645
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
44743
44646
  if (Array.isArray(value)) {
44744
- return value.map((item, i) => /* @__PURE__ */ jsx(React90__default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
44647
+ return value.map((item, i) => /* @__PURE__ */ jsx(React88__default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
44745
44648
  }
44746
44649
  if (typeof value === "object") {
44747
44650
  const rec = value;
@@ -45058,7 +44961,6 @@ function HexStrategyBoard({
45058
44961
  units,
45059
44962
  features,
45060
44963
  assetManifest,
45061
- assetBaseUrl,
45062
44964
  scale,
45063
44965
  showMinimap,
45064
44966
  enableCamera,
@@ -45100,7 +45002,6 @@ function HolidayRunnerBoard({
45100
45002
  units,
45101
45003
  features,
45102
45004
  assetManifest,
45103
- assetBaseUrl,
45104
45005
  scale,
45105
45006
  showMinimap,
45106
45007
  enableCamera,
@@ -45454,7 +45355,7 @@ var init_List = __esm({
45454
45355
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
45455
45356
  return [];
45456
45357
  }, [entity]);
45457
- const getItemActions = React90__default.useCallback(
45358
+ const getItemActions = React88__default.useCallback(
45458
45359
  (item) => {
45459
45360
  if (!itemActions) return [];
45460
45361
  if (typeof itemActions === "function") {
@@ -45895,7 +45796,6 @@ function MatchPuzzleBoard({
45895
45796
  units,
45896
45797
  features,
45897
45798
  assetManifest,
45898
- assetBaseUrl,
45899
45799
  scale,
45900
45800
  showMinimap,
45901
45801
  enableCamera,
@@ -45971,7 +45871,7 @@ var init_MediaGallery = __esm({
45971
45871
  [selectable, selectedItems, selectionEvent, eventBus]
45972
45872
  );
45973
45873
  const entityData = Array.isArray(entity) ? entity : [];
45974
- const items = React90__default.useMemo(() => {
45874
+ const items = React88__default.useMemo(() => {
45975
45875
  if (propItems) return propItems;
45976
45876
  if (entityData.length === 0) return [];
45977
45877
  return entityData.map((record, idx) => {
@@ -46156,7 +46056,6 @@ function MinigolfBoard({
46156
46056
  units,
46157
46057
  features,
46158
46058
  assetManifest,
46159
- assetBaseUrl,
46160
46059
  scale,
46161
46060
  showMinimap,
46162
46061
  enableCamera,
@@ -46176,7 +46075,7 @@ var init_MinigolfBoard = __esm({
46176
46075
  }
46177
46076
  });
46178
46077
  function extractTitle2(children) {
46179
- if (!React90__default.isValidElement(children)) return void 0;
46078
+ if (!React88__default.isValidElement(children)) return void 0;
46180
46079
  const props = children.props;
46181
46080
  if (typeof props.title === "string") {
46182
46081
  return props.title;
@@ -46462,7 +46361,6 @@ function PirateBoard({
46462
46361
  units,
46463
46362
  features,
46464
46363
  assetManifest,
46465
- assetBaseUrl,
46466
46364
  scale,
46467
46365
  showMinimap,
46468
46366
  enableCamera,
@@ -46583,8 +46481,8 @@ function PlatformerBoard({
46583
46481
  canvasHeight,
46584
46482
  followCamera: true,
46585
46483
  bgColor,
46586
- playerSprite,
46587
- tileSprites,
46484
+ playerSprite: playerSprite?.url,
46485
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
46588
46486
  leftEvent,
46589
46487
  rightEvent,
46590
46488
  jumpEvent,
@@ -46649,7 +46547,7 @@ function PlatformerTemplate({
46649
46547
  worldHeight = 400,
46650
46548
  canvasWidth = 800,
46651
46549
  canvasHeight = 400,
46652
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
46550
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
46653
46551
  tileSprites = DEFAULT_TILE_SPRITES,
46654
46552
  bgColor = "#5c94fc",
46655
46553
  gameEndEvent = "GAME_END",
@@ -46702,13 +46600,14 @@ var init_PlatformerTemplate = __esm({
46702
46600
  init_PlatformerBoard();
46703
46601
  init_GameHud();
46704
46602
  init_ScoreBoard();
46603
+ init_makeAsset();
46705
46604
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
46706
- DEFAULT_TILE_SPRITES = {
46605
+ DEFAULT_TILE_SPRITES = makeAssetMap({
46707
46606
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
46708
46607
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
46709
46608
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
46710
46609
  goal: `${CDN3}/tiles/platformPack_tile007.png`
46711
- };
46610
+ }, "tile");
46712
46611
  DEFAULT_PLATFORMS = [
46713
46612
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
46714
46613
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -46864,7 +46763,6 @@ function RacingBoard({
46864
46763
  units,
46865
46764
  features,
46866
46765
  assetManifest,
46867
- assetBaseUrl,
46868
46766
  scale,
46869
46767
  showMinimap,
46870
46768
  enableCamera,
@@ -46883,27 +46781,18 @@ var init_RacingBoard = __esm({
46883
46781
  RacingBoard.displayName = "RacingBoard";
46884
46782
  }
46885
46783
  });
46886
- function resolveManifestUrl3(manifest, relative) {
46887
- if (relative == null) return void 0;
46888
- if (/^https?:\/\//.test(relative)) return relative;
46889
- const base = manifest?.baseUrl;
46890
- if (base == null) return relative;
46891
- const cleanBase = base.replace(/\/$/, "");
46892
- const cleanRel = relative.replace(/^\//, "");
46893
- return `${cleanBase}/${cleanRel}`;
46894
- }
46895
46784
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
46896
46785
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
46897
46786
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
46898
46787
  const isWall = isBorder || isPillar;
46899
46788
  const terrains = manifest?.terrains;
46900
46789
  if (x === stairsX && y === stairsY) {
46901
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
46790
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
46902
46791
  }
46903
46792
  if (isWall) {
46904
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
46793
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
46905
46794
  }
46906
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
46795
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
46907
46796
  }
46908
46797
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
46909
46798
  const tiles = [];
@@ -46947,7 +46836,7 @@ function RoguelikeBoard({
46947
46836
  x: num(r.x),
46948
46837
  y: num(r.y),
46949
46838
  terrain: r.terrain == null ? void 0 : str(r.terrain),
46950
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
46839
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
46951
46840
  passable: r.passable !== false
46952
46841
  })),
46953
46842
  [board.tiles]
@@ -47027,7 +46916,7 @@ function RoguelikeBoard({
47027
46916
  health: playerHp,
47028
46917
  maxHealth: playerMaxHp,
47029
46918
  unitType: "player",
47030
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
46919
+ sprite: assetManifest?.units?.player
47031
46920
  },
47032
46921
  ...liveEnemies.map((e) => ({
47033
46922
  id: e.id,
@@ -47037,7 +46926,7 @@ function RoguelikeBoard({
47037
46926
  health: e.hp,
47038
46927
  maxHealth: 6,
47039
46928
  unitType: "enemy",
47040
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
46929
+ sprite: assetManifest?.units?.enemy
47041
46930
  }))
47042
46931
  ];
47043
46932
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -47047,7 +46936,7 @@ function RoguelikeBoard({
47047
46936
  x: it.x,
47048
46937
  y: it.y,
47049
46938
  type: it.kind,
47050
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
46939
+ sprite: assetManifest?.features?.[it.kind]
47051
46940
  })),
47052
46941
  [items, assetManifest]
47053
46942
  );
@@ -47108,7 +46997,6 @@ function RoguelikeBoard({
47108
46997
  onTileHover: (x, y) => setHoveredTile({ x, y }),
47109
46998
  onTileLeave: () => setHoveredTile(null),
47110
46999
  scale,
47111
- assetBaseUrl: assetManifest?.baseUrl,
47112
47000
  assetManifest,
47113
47001
  unitScale,
47114
47002
  spriteHeightRatio,
@@ -47168,6 +47056,7 @@ var init_RoguelikeBoard = __esm({
47168
47056
  init_Stack();
47169
47057
  init_IsometricCanvas();
47170
47058
  init_boardEntity();
47059
+ init_makeAsset();
47171
47060
  DUNGEON_GRID_W = 16;
47172
47061
  DUNGEON_GRID_H = 16;
47173
47062
  DEFAULT_ENEMIES = [
@@ -47218,55 +47107,59 @@ function RoguelikeTemplate({
47218
47107
  }
47219
47108
  );
47220
47109
  }
47221
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47110
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47222
47111
  var init_RoguelikeTemplate = __esm({
47223
47112
  "components/game/templates/RoguelikeTemplate.tsx"() {
47224
47113
  init_RoguelikeBoard();
47114
+ init_makeAsset();
47225
47115
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
47116
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
47117
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
47118
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
47119
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
47226
47120
  DEFAULT_ROGUELIKE_TILES = [
47227
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47228
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47229
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47230
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47231
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47232
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47233
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47234
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47235
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47236
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47237
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47238
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47239
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47240
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47241
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47242
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47243
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47244
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47245
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
47246
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47247
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47248
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47249
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47250
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47251
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
47121
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47122
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47123
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47124
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47125
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47126
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
47127
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47128
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47129
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47130
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
47131
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
47132
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
47133
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
47134
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
47135
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
47136
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
47137
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
47138
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
47139
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
47140
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
47141
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47142
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47143
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47144
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47145
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
47252
47146
  ];
47253
47147
  DEFAULT_ROGUELIKE_MANIFEST = {
47254
- baseUrl: CDN4,
47255
- terrains: {
47256
- floor: "/isometric-dungeon/Isometric/dirt_E.png",
47257
- wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
47258
- stairs: "/isometric-dungeon/Isometric/stairs_E.png",
47259
- planks: "/isometric-dungeon/Isometric/planks_E.png"
47260
- },
47148
+ terrains: makeAssetMap({
47149
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
47150
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
47151
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
47152
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
47153
+ }, "tile"),
47261
47154
  units: {
47262
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
47263
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
47155
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
47156
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
47264
47157
  },
47265
- features: {
47266
- health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
47267
- sword: "/isometric-dungeon/Isometric/barrel_E.png",
47268
- shield: "/isometric-dungeon/Isometric/barrel_E.png"
47269
- }
47158
+ features: makeAssetMap({
47159
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
47160
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
47161
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
47162
+ }, "item")
47270
47163
  };
47271
47164
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
47272
47165
  }
@@ -47358,7 +47251,7 @@ var init_debugRegistry = __esm({
47358
47251
  }
47359
47252
  });
47360
47253
  function useDebugData() {
47361
- const [data, setData] = React90.useState(() => ({
47254
+ const [data, setData] = React88.useState(() => ({
47362
47255
  traits: [],
47363
47256
  ticks: [],
47364
47257
  guards: [],
@@ -47372,7 +47265,7 @@ function useDebugData() {
47372
47265
  },
47373
47266
  lastUpdate: Date.now()
47374
47267
  }));
47375
- React90.useEffect(() => {
47268
+ React88.useEffect(() => {
47376
47269
  const updateData = () => {
47377
47270
  setData({
47378
47271
  traits: getAllTraits(),
@@ -47481,12 +47374,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
47481
47374
  return positions;
47482
47375
  }
47483
47376
  function WalkMinimap() {
47484
- const [walkStep, setWalkStep] = React90.useState(null);
47485
- const [traits2, setTraits] = React90.useState([]);
47486
- const [coveredEdges, setCoveredEdges] = React90.useState([]);
47487
- const [completedTraits, setCompletedTraits] = React90.useState(/* @__PURE__ */ new Set());
47488
- const prevTraitRef = React90.useRef(null);
47489
- React90.useEffect(() => {
47377
+ const [walkStep, setWalkStep] = React88.useState(null);
47378
+ const [traits2, setTraits] = React88.useState([]);
47379
+ const [coveredEdges, setCoveredEdges] = React88.useState([]);
47380
+ const [completedTraits, setCompletedTraits] = React88.useState(/* @__PURE__ */ new Set());
47381
+ const prevTraitRef = React88.useRef(null);
47382
+ React88.useEffect(() => {
47490
47383
  const interval = setInterval(() => {
47491
47384
  const w = window;
47492
47385
  const step = w.__orbitalWalkStep;
@@ -47922,15 +47815,15 @@ var init_EntitiesTab = __esm({
47922
47815
  });
47923
47816
  function EventFlowTab({ events: events2 }) {
47924
47817
  const { t } = useTranslate();
47925
- const [filter, setFilter] = React90.useState("all");
47926
- const containerRef = React90.useRef(null);
47927
- const [autoScroll, setAutoScroll] = React90.useState(true);
47928
- React90.useEffect(() => {
47818
+ const [filter, setFilter] = React88.useState("all");
47819
+ const containerRef = React88.useRef(null);
47820
+ const [autoScroll, setAutoScroll] = React88.useState(true);
47821
+ React88.useEffect(() => {
47929
47822
  if (autoScroll && containerRef.current) {
47930
47823
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
47931
47824
  }
47932
47825
  }, [events2.length, autoScroll]);
47933
- const filteredEvents = React90.useMemo(() => {
47826
+ const filteredEvents = React88.useMemo(() => {
47934
47827
  if (filter === "all") return events2;
47935
47828
  return events2.filter((e) => e.type === filter);
47936
47829
  }, [events2, filter]);
@@ -48046,7 +47939,7 @@ var init_EventFlowTab = __esm({
48046
47939
  });
48047
47940
  function GuardsPanel({ guards }) {
48048
47941
  const { t } = useTranslate();
48049
- const [filter, setFilter] = React90.useState("all");
47942
+ const [filter, setFilter] = React88.useState("all");
48050
47943
  if (guards.length === 0) {
48051
47944
  return /* @__PURE__ */ jsx(
48052
47945
  EmptyState,
@@ -48059,7 +47952,7 @@ function GuardsPanel({ guards }) {
48059
47952
  }
48060
47953
  const passedCount = guards.filter((g) => g.result).length;
48061
47954
  const failedCount = guards.length - passedCount;
48062
- const filteredGuards = React90.useMemo(() => {
47955
+ const filteredGuards = React88.useMemo(() => {
48063
47956
  if (filter === "all") return guards;
48064
47957
  if (filter === "passed") return guards.filter((g) => g.result);
48065
47958
  return guards.filter((g) => !g.result);
@@ -48222,10 +48115,10 @@ function EffectBadge({ effect }) {
48222
48115
  }
48223
48116
  function TransitionTimeline({ transitions }) {
48224
48117
  const { t } = useTranslate();
48225
- const containerRef = React90.useRef(null);
48226
- const [autoScroll, setAutoScroll] = React90.useState(true);
48227
- const [expandedId, setExpandedId] = React90.useState(null);
48228
- React90.useEffect(() => {
48118
+ const containerRef = React88.useRef(null);
48119
+ const [autoScroll, setAutoScroll] = React88.useState(true);
48120
+ const [expandedId, setExpandedId] = React88.useState(null);
48121
+ React88.useEffect(() => {
48229
48122
  if (autoScroll && containerRef.current) {
48230
48123
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
48231
48124
  }
@@ -48505,9 +48398,9 @@ function getAllEvents(traits2) {
48505
48398
  function EventDispatcherTab({ traits: traits2, schema }) {
48506
48399
  const eventBus = useEventBus();
48507
48400
  const { t } = useTranslate();
48508
- const [log13, setLog] = React90.useState([]);
48509
- const prevStatesRef = React90.useRef(/* @__PURE__ */ new Map());
48510
- React90.useEffect(() => {
48401
+ const [log13, setLog] = React88.useState([]);
48402
+ const prevStatesRef = React88.useRef(/* @__PURE__ */ new Map());
48403
+ React88.useEffect(() => {
48511
48404
  for (const trait of traits2) {
48512
48405
  const prev = prevStatesRef.current.get(trait.id);
48513
48406
  if (prev && prev !== trait.currentState) {
@@ -48676,10 +48569,10 @@ function VerifyModePanel({
48676
48569
  localCount
48677
48570
  }) {
48678
48571
  const { t } = useTranslate();
48679
- const [expanded, setExpanded] = React90.useState(true);
48680
- const scrollRef = React90.useRef(null);
48681
- const prevCountRef = React90.useRef(0);
48682
- React90.useEffect(() => {
48572
+ const [expanded, setExpanded] = React88.useState(true);
48573
+ const scrollRef = React88.useRef(null);
48574
+ const prevCountRef = React88.useRef(0);
48575
+ React88.useEffect(() => {
48683
48576
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
48684
48577
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
48685
48578
  }
@@ -48736,10 +48629,10 @@ function RuntimeDebugger({
48736
48629
  schema
48737
48630
  }) {
48738
48631
  const { t } = useTranslate();
48739
- const [isCollapsed, setIsCollapsed] = React90.useState(mode === "verify" ? true : defaultCollapsed);
48740
- const [isVisible, setIsVisible] = React90.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
48632
+ const [isCollapsed, setIsCollapsed] = React88.useState(mode === "verify" ? true : defaultCollapsed);
48633
+ const [isVisible, setIsVisible] = React88.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
48741
48634
  const debugData = useDebugData();
48742
- React90.useEffect(() => {
48635
+ React88.useEffect(() => {
48743
48636
  if (mode === "inline") return;
48744
48637
  return onDebugToggle((enabled) => {
48745
48638
  setIsVisible(enabled);
@@ -48748,7 +48641,7 @@ function RuntimeDebugger({
48748
48641
  }
48749
48642
  });
48750
48643
  }, [mode]);
48751
- React90.useEffect(() => {
48644
+ React88.useEffect(() => {
48752
48645
  if (mode === "inline") return;
48753
48646
  const handleKeyDown = (e) => {
48754
48647
  if (e.key === "`" && isVisible) {
@@ -49308,7 +49201,7 @@ function SequenceBar({
49308
49201
  onSlotRemove(index);
49309
49202
  }, [onSlotRemove, playing]);
49310
49203
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
49311
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
49204
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React88__default.Fragment, { children: [
49312
49205
  i > 0 && /* @__PURE__ */ jsx(
49313
49206
  Typography,
49314
49207
  {
@@ -50121,7 +50014,6 @@ function SokobanBoard({
50121
50014
  units,
50122
50015
  features,
50123
50016
  assetManifest,
50124
- assetBaseUrl,
50125
50017
  scale,
50126
50018
  showMinimap,
50127
50019
  enableCamera,
@@ -50163,7 +50055,6 @@ function SpaceShmupBoard({
50163
50055
  units,
50164
50056
  features,
50165
50057
  assetManifest,
50166
- assetBaseUrl,
50167
50058
  scale,
50168
50059
  showMinimap,
50169
50060
  enableCamera,
@@ -50205,7 +50096,6 @@ function SpaceStationBoard({
50205
50096
  units,
50206
50097
  features,
50207
50098
  assetManifest,
50208
- assetBaseUrl,
50209
50099
  scale,
50210
50100
  showMinimap,
50211
50101
  enableCamera,
@@ -50340,7 +50230,6 @@ function SportsBoard({
50340
50230
  units,
50341
50231
  features,
50342
50232
  assetManifest,
50343
- assetBaseUrl,
50344
50233
  scale,
50345
50234
  showMinimap,
50346
50235
  enableCamera,
@@ -50397,7 +50286,7 @@ var init_StatCard = __esm({
50397
50286
  const labelToUse = propLabel ?? propTitle;
50398
50287
  const eventBus = useEventBus();
50399
50288
  const { t } = useTranslate();
50400
- const handleActionClick = React90__default.useCallback(() => {
50289
+ const handleActionClick = React88__default.useCallback(() => {
50401
50290
  if (action?.event) {
50402
50291
  eventBus.emit(`UI:${action.event}`, {});
50403
50292
  }
@@ -50408,7 +50297,7 @@ var init_StatCard = __esm({
50408
50297
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
50409
50298
  const isLoading = externalLoading ?? false;
50410
50299
  const error = externalError;
50411
- const computeMetricValue = React90__default.useCallback(
50300
+ const computeMetricValue = React88__default.useCallback(
50412
50301
  (metric, items) => {
50413
50302
  if (metric.value !== void 0) {
50414
50303
  return metric.value;
@@ -50447,7 +50336,7 @@ var init_StatCard = __esm({
50447
50336
  },
50448
50337
  []
50449
50338
  );
50450
- const schemaStats = React90__default.useMemo(() => {
50339
+ const schemaStats = React88__default.useMemo(() => {
50451
50340
  if (!metrics || metrics.length === 0) return null;
50452
50341
  return metrics.map((metric) => ({
50453
50342
  label: metric.label,
@@ -50455,7 +50344,7 @@ var init_StatCard = __esm({
50455
50344
  format: metric.format
50456
50345
  }));
50457
50346
  }, [metrics, data, computeMetricValue]);
50458
- const calculatedTrend = React90__default.useMemo(() => {
50347
+ const calculatedTrend = React88__default.useMemo(() => {
50459
50348
  if (manualTrend !== void 0) return manualTrend;
50460
50349
  if (previousValue === void 0 || currentValue === void 0)
50461
50350
  return void 0;
@@ -51661,8 +51550,8 @@ var init_SubagentTracePanel = __esm({
51661
51550
  ] });
51662
51551
  };
51663
51552
  InlineActivityStream = ({ activities, autoScroll = true, className }) => {
51664
- const endRef = React90__default.useRef(null);
51665
- React90__default.useEffect(() => {
51553
+ const endRef = React88__default.useRef(null);
51554
+ React88__default.useEffect(() => {
51666
51555
  if (!autoScroll) return;
51667
51556
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
51668
51557
  }, [activities.length, autoScroll]);
@@ -51756,7 +51645,7 @@ var init_SubagentTracePanel = __esm({
51756
51645
  };
51757
51646
  SubagentRichCard = ({ subagent }) => {
51758
51647
  const { t } = useTranslate();
51759
- const activities = React90__default.useMemo(
51648
+ const activities = React88__default.useMemo(
51760
51649
  () => subagentMessagesToActivities(subagent.messages),
51761
51650
  [subagent.messages]
51762
51651
  );
@@ -51833,8 +51722,8 @@ var init_SubagentTracePanel = __esm({
51833
51722
  ] });
51834
51723
  };
51835
51724
  CoordinatorConversation = ({ messages, autoScroll = true, className }) => {
51836
- const endRef = React90__default.useRef(null);
51837
- React90__default.useEffect(() => {
51725
+ const endRef = React88__default.useRef(null);
51726
+ React88__default.useEffect(() => {
51838
51727
  if (!autoScroll) return;
51839
51728
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
51840
51729
  }, [messages.length, autoScroll]);
@@ -52184,7 +52073,6 @@ function TanksBoard({
52184
52073
  units,
52185
52074
  features,
52186
52075
  assetManifest,
52187
- assetBaseUrl,
52188
52076
  scale,
52189
52077
  showMinimap,
52190
52078
  enableCamera,
@@ -52306,7 +52194,7 @@ var init_Timeline = __esm({
52306
52194
  }) => {
52307
52195
  const { t } = useTranslate();
52308
52196
  const entityData = entity ?? [];
52309
- const items = React90__default.useMemo(() => {
52197
+ const items = React88__default.useMemo(() => {
52310
52198
  if (propItems) return propItems;
52311
52199
  if (entityData.length === 0) return [];
52312
52200
  return entityData.map((record, idx) => {
@@ -52408,7 +52296,7 @@ var init_Timeline = __esm({
52408
52296
  }
52409
52297
  });
52410
52298
  function extractToastProps(children) {
52411
- if (!React90__default.isValidElement(children)) {
52299
+ if (!React88__default.isValidElement(children)) {
52412
52300
  if (typeof children === "string") {
52413
52301
  return { message: children };
52414
52302
  }
@@ -52446,7 +52334,7 @@ var init_ToastSlot = __esm({
52446
52334
  eventBus.emit("UI:CLOSE");
52447
52335
  };
52448
52336
  if (!isVisible) return null;
52449
- const isCustomContent = React90__default.isValidElement(children) && !message;
52337
+ const isCustomContent = React88__default.isValidElement(children) && !message;
52450
52338
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
52451
52339
  Toast,
52452
52340
  {
@@ -52462,15 +52350,6 @@ var init_ToastSlot = __esm({
52462
52350
  ToastSlot.displayName = "ToastSlot";
52463
52351
  }
52464
52352
  });
52465
- function resolveManifestUrl4(manifest, relative) {
52466
- if (relative == null || relative === "") return void 0;
52467
- if (/^https?:\/\//.test(relative)) return relative;
52468
- const base = manifest?.baseUrl;
52469
- if (base == null) return relative;
52470
- const cleanBase = base.replace(/\/$/, "");
52471
- const cleanRel = relative.replace(/^\//, "");
52472
- return `${cleanBase}/${cleanRel}`;
52473
- }
52474
52353
  function readPlayer(v) {
52475
52354
  if (v == null || typeof v !== "object") return void 0;
52476
52355
  const o = v;
@@ -52523,10 +52402,10 @@ function TopDownShooterBoard({
52523
52402
  const wave = propWave ?? num(board.wave, 1);
52524
52403
  const lives = propLives ?? num(board.lives, 3);
52525
52404
  const result = propResult ?? (str(board.result) || "none");
52526
- const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
52527
- const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
52528
- const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
52529
- const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
52405
+ const playerSprite = assetManifest?.units?.player?.url;
52406
+ const enemySprite = assetManifest?.units?.enemy?.url;
52407
+ const projectileSprite = assetManifest?.features?.projectile?.url;
52408
+ const backgroundSprite = assetManifest?.background;
52530
52409
  const spriteUrls = useMemo(
52531
52410
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
52532
52411
  [playerSprite, enemySprite, projectileSprite]
@@ -52693,7 +52572,6 @@ function TopDownShooterBoard({
52693
52572
  width,
52694
52573
  height,
52695
52574
  backgroundImage: backgroundSprite,
52696
- assetBaseUrl: assetManifest?.baseUrl,
52697
52575
  onDraw
52698
52576
  }
52699
52577
  ),
@@ -52818,15 +52696,6 @@ var init_TopDownShooterTemplate = __esm({
52818
52696
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
52819
52697
  }
52820
52698
  });
52821
- function resolveManifestUrl5(manifest, relative) {
52822
- if (relative == null) return void 0;
52823
- if (/^https?:\/\//.test(relative)) return relative;
52824
- const base = manifest?.baseUrl;
52825
- if (base == null) return relative;
52826
- const cleanBase = base.replace(/\/$/, "");
52827
- const cleanRel = relative.replace(/^\//, "");
52828
- return `${cleanBase}/${cleanRel}`;
52829
- }
52830
52699
  function buildDefaultTDTiles() {
52831
52700
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
52832
52701
  const tiles = [];
@@ -52846,18 +52715,18 @@ function buildDefaultTDTiles() {
52846
52715
  function tilesToIso2(tiles, manifest) {
52847
52716
  return tiles.map((t) => {
52848
52717
  const key = t.terrain ?? "ground";
52849
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
52718
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
52850
52719
  return {
52851
52720
  x: t.x,
52852
52721
  y: t.y,
52853
52722
  terrain: t.terrain,
52854
- terrainSprite: sprite,
52723
+ terrainSprite,
52855
52724
  passable: t.passable
52856
52725
  };
52857
52726
  });
52858
52727
  }
52859
52728
  function creepsToUnits(creeps, manifest) {
52860
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
52729
+ const sprite = manifest?.units?.creep;
52861
52730
  return creeps.map((c) => ({
52862
52731
  id: c.id,
52863
52732
  position: { x: c.x, y: c.y },
@@ -52875,14 +52744,14 @@ function heroToUnit(hero, manifest) {
52875
52744
  position: { x: hero.x, y: hero.y },
52876
52745
  name: "Hero",
52877
52746
  team: "player",
52878
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
52747
+ sprite: manifest?.units?.hero,
52879
52748
  unitType: "hero",
52880
52749
  health: 1,
52881
52750
  maxHealth: 1
52882
52751
  };
52883
52752
  }
52884
52753
  function towersToFeatures(towers, manifest) {
52885
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
52754
+ const sprite = manifest?.features?.tower;
52886
52755
  return towers.map((t) => ({
52887
52756
  id: t.id,
52888
52757
  x: t.x,
@@ -53080,7 +52949,6 @@ function TowerDefenseBoard({
53080
52949
  tiles: isoTiles,
53081
52950
  units: isoUnits,
53082
52951
  features: towerFeatures,
53083
- assetBaseUrl: assetManifest?.baseUrl,
53084
52952
  assetManifest,
53085
52953
  validMoves,
53086
52954
  hoveredTile,
@@ -53124,6 +52992,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
53124
52992
  var init_TowerDefenseBoard = __esm({
53125
52993
  "components/game/organisms/TowerDefenseBoard.tsx"() {
53126
52994
  "use client";
52995
+ init_makeAsset();
53127
52996
  init_cn();
53128
52997
  init_useEventBus();
53129
52998
  init_Box();
@@ -53453,15 +53322,6 @@ var init_UncontrolledBattleBoard = __esm({
53453
53322
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
53454
53323
  }
53455
53324
  });
53456
- function resolveManifestUrl6(manifest, relative) {
53457
- if (relative == null) return void 0;
53458
- if (/^https?:\/\//.test(relative)) return relative;
53459
- const base = manifest?.baseUrl;
53460
- if (base == null) return relative;
53461
- const cleanBase = base.replace(/\/$/, "");
53462
- const cleanRel = relative.replace(/^\//, "");
53463
- return `${cleanBase}/${cleanRel}`;
53464
- }
53465
53325
  function VisualNovelBoard({
53466
53326
  entity,
53467
53327
  nodes: propNodes,
@@ -53496,11 +53356,11 @@ function VisualNovelBoard({
53496
53356
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
53497
53357
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
53498
53358
  const backgroundImage = useMemo(
53499
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
53359
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
53500
53360
  [assetManifest, currentNode?.backgroundKey]
53501
53361
  );
53502
53362
  const portraitUrl = useMemo(
53503
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
53363
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
53504
53364
  [assetManifest, currentNode?.portraitKey]
53505
53365
  );
53506
53366
  const dialogueChoices = useMemo(
@@ -53674,7 +53534,7 @@ function buildDefaultWorldTiles() {
53674
53534
  for (let x = 0; x < WORLD_GRID_W; x++) {
53675
53535
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
53676
53536
  const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
53677
- tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
53537
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
53678
53538
  }
53679
53539
  }
53680
53540
  return tiles;
@@ -53718,7 +53578,12 @@ function WorldMapBoard({
53718
53578
  const resolved = boardEntity(entity);
53719
53579
  const entityUnits = rows(resolved?.units);
53720
53580
  const entityTiles = rows(resolved?.tiles);
53721
- const features = propFeatures ?? rows(resolved?.features);
53581
+ const features = propFeatures ?? rows(resolved?.features).map((r) => ({
53582
+ id: r.id == null ? void 0 : str(r.id),
53583
+ x: num(r.x),
53584
+ y: num(r.y),
53585
+ type: str(r.type)
53586
+ }));
53722
53587
  const selectedHeroId = resolved?.selectedHeroId ?? null;
53723
53588
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
53724
53589
  const backgroundImage = resolved?.backgroundImage;
@@ -53728,7 +53593,7 @@ function WorldMapBoard({
53728
53593
  x: num(t.x),
53729
53594
  y: num(t.y),
53730
53595
  terrain: str(t.terrain),
53731
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
53596
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
53732
53597
  passable: t.passable !== false
53733
53598
  })),
53734
53599
  [entityTiles]
@@ -53744,7 +53609,7 @@ function WorldMapBoard({
53744
53609
  team: str(u.team) === "enemy" ? "enemy" : "player",
53745
53610
  health: num(u.health) || 100,
53746
53611
  maxHealth: num(u.maxHealth) || 100,
53747
- sprite: u.sprite == null ? void 0 : str(u.sprite)
53612
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
53748
53613
  })),
53749
53614
  [entityUnits, propUnits]
53750
53615
  );
@@ -53926,7 +53791,6 @@ function WorldMapBoard({
53926
53791
  onTileHover: (x, y) => setHoveredTile({ x, y }),
53927
53792
  onTileLeave: () => setHoveredTile(null),
53928
53793
  scale,
53929
- assetBaseUrl: assetManifest?.baseUrl,
53930
53794
  assetManifest,
53931
53795
  backgroundImage,
53932
53796
  effectSpriteUrls,
@@ -53949,6 +53813,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
53949
53813
  var init_WorldMapBoard = __esm({
53950
53814
  "components/game/organisms/WorldMapBoard.tsx"() {
53951
53815
  "use client";
53816
+ init_makeAsset();
53952
53817
  init_cn();
53953
53818
  init_useEventBus();
53954
53819
  init_Stack();
@@ -54002,68 +53867,72 @@ function WorldMapTemplate({
54002
53867
  }
54003
53868
  );
54004
53869
  }
54005
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
53870
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
54006
53871
  var init_WorldMapTemplate = __esm({
54007
53872
  "components/game/templates/WorldMapTemplate.tsx"() {
54008
53873
  init_WorldMapBoard();
53874
+ init_makeAsset();
54009
53875
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
53876
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
53877
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
53878
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
53879
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
54010
53880
  DEFAULT_WORLDMAP_TILES = [
54011
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54012
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54013
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
54014
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54015
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54016
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54017
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54018
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54019
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54020
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
54021
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
54022
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54023
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
54024
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54025
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54026
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54027
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54028
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54029
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
54030
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54031
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54032
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
54033
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
54034
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
54035
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
53881
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53882
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53883
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
53884
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53885
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53886
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
53887
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53888
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53889
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53890
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
53891
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
53892
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
53893
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
53894
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
53895
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
53896
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
53897
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
53898
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
53899
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
53900
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
53901
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
53902
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
53903
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
53904
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
53905
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
54036
53906
  ];
54037
53907
  DEFAULT_WORLDMAP_UNITS = [
54038
- { 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` },
54039
- { 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` }
53908
+ { id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player") },
53909
+ { id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc") }
54040
53910
  ];
54041
53911
  DEFAULT_WORLDMAP_FEATURES = [
54042
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
54043
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
53912
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
53913
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
54044
53914
  ];
54045
53915
  DEFAULT_WORLDMAP_MANIFEST = {
54046
- baseUrl: CDN5,
54047
- terrains: {
54048
- grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
54049
- water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
54050
- mountain: "/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png",
54051
- road: "/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png"
54052
- },
53916
+ terrains: makeAssetMap({
53917
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
53918
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
53919
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
53920
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
53921
+ }, "tile"),
54053
53922
  units: {
54054
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
54055
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
53923
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
53924
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
54056
53925
  },
54057
- features: {
54058
- capital: "/scenes/world/capital.png",
54059
- power_node: "/world-map/power_node.png"
54060
- }
53926
+ features: makeAssetMap({
53927
+ capital: `${CDN5}/scenes/world/capital.png`,
53928
+ power_node: `${CDN5}/world-map/power_node.png`
53929
+ }, "decoration")
54061
53930
  };
54062
53931
  WorldMapTemplate.displayName = "WorldMapTemplate";
54063
53932
  }
54064
53933
  });
54065
53934
  function lazyThree(name, loader) {
54066
- const Lazy = React90__default.lazy(
53935
+ const Lazy = React88__default.lazy(
54067
53936
  () => loader().then((m) => {
54068
53937
  const Resolved = m[name];
54069
53938
  if (!Resolved) {
@@ -54075,13 +53944,13 @@ function lazyThree(name, loader) {
54075
53944
  })
54076
53945
  );
54077
53946
  function ThreeWrapper(props) {
54078
- return React90__default.createElement(
53947
+ return React88__default.createElement(
54079
53948
  ThreeBoundary,
54080
53949
  { name },
54081
- React90__default.createElement(
54082
- React90__default.Suspense,
53950
+ React88__default.createElement(
53951
+ React88__default.Suspense,
54083
53952
  { fallback: null },
54084
- React90__default.createElement(Lazy, props)
53953
+ React88__default.createElement(Lazy, props)
54085
53954
  )
54086
53955
  );
54087
53956
  }
@@ -54404,7 +54273,7 @@ var init_component_registry_generated = __esm({
54404
54273
  init_WorldMapBoard();
54405
54274
  init_WorldMapTemplate();
54406
54275
  init_XPBar();
54407
- ThreeBoundary = class extends React90__default.Component {
54276
+ ThreeBoundary = class extends React88__default.Component {
54408
54277
  constructor() {
54409
54278
  super(...arguments);
54410
54279
  __publicField(this, "state", { failed: false });
@@ -54414,7 +54283,7 @@ var init_component_registry_generated = __esm({
54414
54283
  }
54415
54284
  render() {
54416
54285
  if (this.state.failed) {
54417
- return React90__default.createElement(
54286
+ return React88__default.createElement(
54418
54287
  "div",
54419
54288
  {
54420
54289
  "data-testid": "three-unavailable",
@@ -54780,7 +54649,7 @@ function SuspenseConfigProvider({
54780
54649
  config,
54781
54650
  children
54782
54651
  }) {
54783
- return React90__default.createElement(
54652
+ return React88__default.createElement(
54784
54653
  SuspenseConfigContext.Provider,
54785
54654
  { value: config },
54786
54655
  children
@@ -54822,7 +54691,7 @@ function enrichFormFields(fields, entityDef) {
54822
54691
  }
54823
54692
  return { name: field, label: field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()) };
54824
54693
  }
54825
- if (field && typeof field === "object" && !Array.isArray(field) && !React90__default.isValidElement(field) && !(field instanceof Date)) {
54694
+ if (field && typeof field === "object" && !Array.isArray(field) && !React88__default.isValidElement(field) && !(field instanceof Date)) {
54826
54695
  const obj = field;
54827
54696
  const fieldName = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
54828
54697
  if (!fieldName) return field;
@@ -55268,7 +55137,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
55268
55137
  const key = `${parentId}-${index}-trait:${traitName}`;
55269
55138
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
55270
55139
  }
55271
- return /* @__PURE__ */ jsx(React90__default.Fragment, { children: child }, `${parentId}-${index}`);
55140
+ return /* @__PURE__ */ jsx(React88__default.Fragment, { children: child }, `${parentId}-${index}`);
55272
55141
  }
55273
55142
  if (!child || typeof child !== "object") return null;
55274
55143
  const childId = `${parentId}-${index}`;
@@ -55308,14 +55177,14 @@ function isPatternConfig(value) {
55308
55177
  if (value === null || value === void 0) return false;
55309
55178
  if (typeof value !== "object") return false;
55310
55179
  if (Array.isArray(value)) return false;
55311
- if (React90__default.isValidElement(value)) return false;
55180
+ if (React88__default.isValidElement(value)) return false;
55312
55181
  if (value instanceof Date) return false;
55313
55182
  if (typeof value === "function") return false;
55314
55183
  const record = value;
55315
55184
  return "type" in record && typeof record.type === "string" && getComponentForPattern(record.type) !== null;
55316
55185
  }
55317
55186
  function isPlainConfigObject(value) {
55318
- if (React90__default.isValidElement(value)) return false;
55187
+ if (React88__default.isValidElement(value)) return false;
55319
55188
  if (value instanceof Date) return false;
55320
55189
  const proto = Object.getPrototypeOf(value);
55321
55190
  return proto === Object.prototype || proto === null;
@@ -55441,7 +55310,7 @@ function SlotContentRenderer({
55441
55310
  for (const slotKey of CONTENT_NODE_SLOTS) {
55442
55311
  const slotVal = restProps[slotKey];
55443
55312
  if (slotVal === void 0 || slotVal === null) continue;
55444
- if (React90__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
55313
+ if (React88__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
55445
55314
  if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
55446
55315
  nodeSlotOverrides[slotKey] = renderPatternChildren(
55447
55316
  slotVal,
@@ -55490,7 +55359,7 @@ function SlotContentRenderer({
55490
55359
  const resolvedItems = Array.isArray(entityVal) && entityVal[0] !== "fn" ? entityVal : null;
55491
55360
  if (resolvedItems && resolvedItems.length > 0 && !finalProps.fields && !finalProps.columns) {
55492
55361
  const sample = resolvedItems[0];
55493
- if (sample && typeof sample === "object" && !Array.isArray(sample) && !React90__default.isValidElement(sample) && !(sample instanceof Date)) {
55362
+ if (sample && typeof sample === "object" && !Array.isArray(sample) && !React88__default.isValidElement(sample) && !(sample instanceof Date)) {
55494
55363
  const keys = Object.keys(sample).filter((k) => k !== "id" && k !== "_id");
55495
55364
  finalProps.fields = keys.map((k, i) => ({ name: k, variant: i === 0 ? "h4" : "body" }));
55496
55365
  }