@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
package/dist/avl/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import * as React98 from 'react';
3
- import React98__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
2
+ import * as React96 from 'react';
3
+ import React96__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
4
4
  import { OrbitalProvider, EventBusContext, useTraitScope, VerificationProvider, TraitScopeProvider } from '@almadar/ui/providers';
5
5
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
6
6
  import ELK from 'elkjs/lib/elk.bundled.js';
@@ -3181,7 +3181,7 @@ var init_Typography = __esm({
3181
3181
  }) => {
3182
3182
  const variant = variantProp ?? (level ? `h${level}` : "body1");
3183
3183
  const Component2 = as || defaultElements[variant];
3184
- return React98__default.createElement(
3184
+ return React96__default.createElement(
3185
3185
  Component2,
3186
3186
  {
3187
3187
  id,
@@ -3518,7 +3518,7 @@ var init_Box = __esm({
3518
3518
  fixed: "fixed",
3519
3519
  sticky: "sticky"
3520
3520
  };
3521
- Box = React98__default.forwardRef(
3521
+ Box = React96__default.forwardRef(
3522
3522
  ({
3523
3523
  padding,
3524
3524
  paddingX,
@@ -3583,7 +3583,7 @@ var init_Box = __esm({
3583
3583
  onPointerDown?.(e);
3584
3584
  }, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
3585
3585
  const isClickable = action || onClick;
3586
- return React98__default.createElement(
3586
+ return React96__default.createElement(
3587
3587
  Component2,
3588
3588
  {
3589
3589
  ref,
@@ -3679,7 +3679,7 @@ var init_Stack = __esm({
3679
3679
  };
3680
3680
  const isHorizontal = direction === "horizontal";
3681
3681
  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";
3682
- return React98__default.createElement(
3682
+ return React96__default.createElement(
3683
3683
  Component2,
3684
3684
  {
3685
3685
  className: cn(
@@ -4171,7 +4171,7 @@ var init_MiniStateMachine = __esm({
4171
4171
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
4172
4172
  const tc = transitionCounts[s.name] ?? 0;
4173
4173
  const role = getStateRole(s.name, s.isInitial ?? void 0, s.isTerminal ?? void 0, tc, maxTC);
4174
- return /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
4174
+ return /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
4175
4175
  /* @__PURE__ */ jsx(
4176
4176
  AvlState,
4177
4177
  {
@@ -4546,7 +4546,7 @@ function loadLib(key, importer) {
4546
4546
  return p2;
4547
4547
  }
4548
4548
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4549
- const Lazy = React98__default.lazy(async () => {
4549
+ const Lazy = React96__default.lazy(async () => {
4550
4550
  const lib = await loadLib(libKey, importer);
4551
4551
  const Comp = pick(lib);
4552
4552
  if (!Comp) {
@@ -4556,7 +4556,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4556
4556
  return { default: Comp };
4557
4557
  });
4558
4558
  const Wrapped = (props) => /* @__PURE__ */ jsx(
4559
- React98__default.Suspense,
4559
+ React96__default.Suspense,
4560
4560
  {
4561
4561
  fallback: /* @__PURE__ */ jsx(
4562
4562
  "span",
@@ -5283,7 +5283,7 @@ var init_Icon = __esm({
5283
5283
  const directIcon = typeof icon === "string" ? void 0 : icon;
5284
5284
  const effectiveName = typeof icon === "string" ? icon : name;
5285
5285
  const family = useIconFamily();
5286
- const RenderedComponent = React98__default.useMemo(() => {
5286
+ const RenderedComponent = React96__default.useMemo(() => {
5287
5287
  if (directIcon) return null;
5288
5288
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
5289
5289
  }, [directIcon, effectiveName, family]);
@@ -5345,7 +5345,7 @@ function resolveIconProp(value, sizeClass) {
5345
5345
  const IconComp = value;
5346
5346
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
5347
5347
  }
5348
- if (React98__default.isValidElement(value)) {
5348
+ if (React96__default.isValidElement(value)) {
5349
5349
  return value;
5350
5350
  }
5351
5351
  if (typeof value === "object" && value !== null && isIconLike(value)) {
@@ -5421,7 +5421,7 @@ var init_Button = __esm({
5421
5421
  md: "h-icon-default w-icon-default",
5422
5422
  lg: "h-icon-default w-icon-default"
5423
5423
  };
5424
- Button = React98__default.forwardRef(
5424
+ Button = React96__default.forwardRef(
5425
5425
  ({
5426
5426
  className,
5427
5427
  variant = "primary",
@@ -5487,7 +5487,7 @@ var Dialog;
5487
5487
  var init_Dialog = __esm({
5488
5488
  "components/core/atoms/Dialog.tsx"() {
5489
5489
  init_cn();
5490
- Dialog = React98__default.forwardRef(
5490
+ Dialog = React96__default.forwardRef(
5491
5491
  ({
5492
5492
  role = "dialog",
5493
5493
  "aria-modal": ariaModal = true,
@@ -5982,7 +5982,7 @@ var init_Badge = __esm({
5982
5982
  md: "px-2.5 py-1 text-sm",
5983
5983
  lg: "px-3 py-1.5 text-base"
5984
5984
  };
5985
- Badge = React98__default.forwardRef(
5985
+ Badge = React96__default.forwardRef(
5986
5986
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
5987
5987
  const iconSizes3 = {
5988
5988
  sm: "h-icon-default w-icon-default",
@@ -6318,7 +6318,7 @@ var init_SvgFlow = __esm({
6318
6318
  width = 100,
6319
6319
  height = 100
6320
6320
  }) => {
6321
- const markerId = React98__default.useMemo(() => {
6321
+ const markerId = React96__default.useMemo(() => {
6322
6322
  flowIdCounter += 1;
6323
6323
  return `almadar-flow-arrow-${flowIdCounter}`;
6324
6324
  }, []);
@@ -6911,7 +6911,7 @@ var init_SvgRing = __esm({
6911
6911
  width = 100,
6912
6912
  height = 100
6913
6913
  }) => {
6914
- const gradientId = React98__default.useMemo(() => {
6914
+ const gradientId = React96__default.useMemo(() => {
6915
6915
  ringIdCounter += 1;
6916
6916
  return `almadar-ring-glow-${ringIdCounter}`;
6917
6917
  }, []);
@@ -7092,7 +7092,7 @@ var init_Input = __esm({
7092
7092
  init_cn();
7093
7093
  init_Icon();
7094
7094
  init_useEventBus();
7095
- Input = React98__default.forwardRef(
7095
+ Input = React96__default.forwardRef(
7096
7096
  ({
7097
7097
  className,
7098
7098
  inputType,
@@ -7252,7 +7252,7 @@ var Label;
7252
7252
  var init_Label = __esm({
7253
7253
  "components/core/atoms/Label.tsx"() {
7254
7254
  init_cn();
7255
- Label = React98__default.forwardRef(
7255
+ Label = React96__default.forwardRef(
7256
7256
  ({ className, required, children, ...props }, ref) => {
7257
7257
  return /* @__PURE__ */ jsxs(
7258
7258
  "label",
@@ -7279,7 +7279,7 @@ var init_Textarea = __esm({
7279
7279
  "components/core/atoms/Textarea.tsx"() {
7280
7280
  init_cn();
7281
7281
  init_useEventBus();
7282
- Textarea = React98__default.forwardRef(
7282
+ Textarea = React96__default.forwardRef(
7283
7283
  ({ className, error, onChange, ...props }, ref) => {
7284
7284
  const eventBus = useEventBus();
7285
7285
  const handleChange = (e) => {
@@ -7518,7 +7518,7 @@ var init_Select = __esm({
7518
7518
  init_cn();
7519
7519
  init_Icon();
7520
7520
  init_useEventBus();
7521
- Select = React98__default.forwardRef(
7521
+ Select = React96__default.forwardRef(
7522
7522
  (props, _ref) => {
7523
7523
  const { multiple, searchable, clearable } = props;
7524
7524
  if (multiple || searchable || clearable) {
@@ -7535,7 +7535,7 @@ var init_Checkbox = __esm({
7535
7535
  "components/core/atoms/Checkbox.tsx"() {
7536
7536
  init_cn();
7537
7537
  init_useEventBus();
7538
- Checkbox = React98__default.forwardRef(
7538
+ Checkbox = React96__default.forwardRef(
7539
7539
  ({ className, label, id, onChange, ...props }, ref) => {
7540
7540
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
7541
7541
  const eventBus = useEventBus();
@@ -7589,7 +7589,7 @@ var init_Spinner = __esm({
7589
7589
  md: "h-6 w-6",
7590
7590
  lg: "h-8 w-8"
7591
7591
  };
7592
- Spinner = React98__default.forwardRef(
7592
+ Spinner = React96__default.forwardRef(
7593
7593
  ({ className, size = "md", overlay, ...props }, ref) => {
7594
7594
  if (overlay) {
7595
7595
  return /* @__PURE__ */ jsx(
@@ -7679,7 +7679,7 @@ var init_Card = __esm({
7679
7679
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
7680
7680
  "tile-image-first": "p-0 overflow-hidden"
7681
7681
  };
7682
- Card = React98__default.forwardRef(
7682
+ Card = React96__default.forwardRef(
7683
7683
  ({
7684
7684
  className,
7685
7685
  variant = "bordered",
@@ -7727,9 +7727,9 @@ var init_Card = __esm({
7727
7727
  }
7728
7728
  );
7729
7729
  Card.displayName = "Card";
7730
- CardHeader = React98__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7730
+ CardHeader = React96__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7731
7731
  CardHeader.displayName = "CardHeader";
7732
- CardTitle = React98__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7732
+ CardTitle = React96__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7733
7733
  "h3",
7734
7734
  {
7735
7735
  ref,
@@ -7742,11 +7742,11 @@ var init_Card = __esm({
7742
7742
  }
7743
7743
  ));
7744
7744
  CardTitle.displayName = "CardTitle";
7745
- CardContent = React98__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7745
+ CardContent = React96__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7746
7746
  CardContent.displayName = "CardContent";
7747
7747
  CardBody = CardContent;
7748
7748
  CardBody.displayName = "CardBody";
7749
- CardFooter = React98__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7749
+ CardFooter = React96__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7750
7750
  "div",
7751
7751
  {
7752
7752
  ref,
@@ -7801,7 +7801,7 @@ var init_FilterPill = __esm({
7801
7801
  md: "w-3.5 h-3.5",
7802
7802
  lg: "w-4 h-4"
7803
7803
  };
7804
- FilterPill = React98__default.forwardRef(
7804
+ FilterPill = React96__default.forwardRef(
7805
7805
  ({
7806
7806
  className,
7807
7807
  variant = "default",
@@ -7930,8 +7930,8 @@ var init_Avatar = __esm({
7930
7930
  actionPayload
7931
7931
  }) => {
7932
7932
  const eventBus = useEventBus();
7933
- const [imgFailed, setImgFailed] = React98__default.useState(false);
7934
- React98__default.useEffect(() => {
7933
+ const [imgFailed, setImgFailed] = React96__default.useState(false);
7934
+ React96__default.useEffect(() => {
7935
7935
  setImgFailed(false);
7936
7936
  }, [src]);
7937
7937
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -8044,7 +8044,7 @@ var init_Center = __esm({
8044
8044
  as: Component2 = "div"
8045
8045
  }) => {
8046
8046
  const mergedStyle = minHeight ? { minHeight, ...style } : style;
8047
- return React98__default.createElement(Component2, {
8047
+ return React96__default.createElement(Component2, {
8048
8048
  className: cn(
8049
8049
  inline ? "inline-flex" : "flex",
8050
8050
  horizontal && "justify-center",
@@ -8312,7 +8312,7 @@ var init_Radio = __esm({
8312
8312
  md: "w-2.5 h-2.5",
8313
8313
  lg: "w-3 h-3"
8314
8314
  };
8315
- Radio = React98__default.forwardRef(
8315
+ Radio = React96__default.forwardRef(
8316
8316
  ({
8317
8317
  label,
8318
8318
  helperText,
@@ -8329,12 +8329,12 @@ var init_Radio = __esm({
8329
8329
  onChange,
8330
8330
  ...props
8331
8331
  }, ref) => {
8332
- const reactId = React98__default.useId();
8332
+ const reactId = React96__default.useId();
8333
8333
  const baseId = id || `radio-${reactId}`;
8334
8334
  const hasError = !!error;
8335
8335
  const eventBus = useEventBus();
8336
- const [selected, setSelected] = React98__default.useState(value);
8337
- React98__default.useEffect(() => {
8336
+ const [selected, setSelected] = React96__default.useState(value);
8337
+ React96__default.useEffect(() => {
8338
8338
  if (value !== void 0) setSelected(value);
8339
8339
  }, [value]);
8340
8340
  const pick = (next, e) => {
@@ -8516,7 +8516,7 @@ var init_Switch = __esm({
8516
8516
  "components/core/atoms/Switch.tsx"() {
8517
8517
  "use client";
8518
8518
  init_cn();
8519
- Switch = React98.forwardRef(
8519
+ Switch = React96.forwardRef(
8520
8520
  ({
8521
8521
  checked,
8522
8522
  defaultChecked = false,
@@ -8527,10 +8527,10 @@ var init_Switch = __esm({
8527
8527
  name,
8528
8528
  className
8529
8529
  }, ref) => {
8530
- const [isChecked, setIsChecked] = React98.useState(
8530
+ const [isChecked, setIsChecked] = React96.useState(
8531
8531
  checked !== void 0 ? checked : defaultChecked
8532
8532
  );
8533
- React98.useEffect(() => {
8533
+ React96.useEffect(() => {
8534
8534
  if (checked !== void 0) {
8535
8535
  setIsChecked(checked);
8536
8536
  }
@@ -8804,7 +8804,7 @@ var Aside;
8804
8804
  var init_Aside = __esm({
8805
8805
  "components/core/atoms/Aside.tsx"() {
8806
8806
  init_cn();
8807
- Aside = React98__default.forwardRef(
8807
+ Aside = React96__default.forwardRef(
8808
8808
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
8809
8809
  );
8810
8810
  Aside.displayName = "Aside";
@@ -8883,9 +8883,9 @@ var init_LawReferenceTooltip = __esm({
8883
8883
  className
8884
8884
  }) => {
8885
8885
  const { t } = useTranslate();
8886
- const [isVisible, setIsVisible] = React98__default.useState(false);
8887
- const timeoutRef = React98__default.useRef(null);
8888
- const triggerRef = React98__default.useRef(null);
8886
+ const [isVisible, setIsVisible] = React96__default.useState(false);
8887
+ const timeoutRef = React96__default.useRef(null);
8888
+ const triggerRef = React96__default.useRef(null);
8889
8889
  const handleMouseEnter = () => {
8890
8890
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8891
8891
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -8896,7 +8896,7 @@ var init_LawReferenceTooltip = __esm({
8896
8896
  };
8897
8897
  const { revealed, triggerProps } = useTapReveal({ refs: [triggerRef] });
8898
8898
  const open = isVisible || revealed;
8899
- React98__default.useEffect(() => {
8899
+ React96__default.useEffect(() => {
8900
8900
  return () => {
8901
8901
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8902
8902
  };
@@ -9108,7 +9108,7 @@ var init_StatusDot = __esm({
9108
9108
  md: "w-2.5 h-2.5",
9109
9109
  lg: "w-3 h-3"
9110
9110
  };
9111
- StatusDot = React98__default.forwardRef(
9111
+ StatusDot = React96__default.forwardRef(
9112
9112
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
9113
9113
  return /* @__PURE__ */ jsx(
9114
9114
  "span",
@@ -9162,7 +9162,7 @@ var init_TrendIndicator = __esm({
9162
9162
  down: "trending-down",
9163
9163
  flat: "arrow-right"
9164
9164
  };
9165
- TrendIndicator = React98__default.forwardRef(
9165
+ TrendIndicator = React96__default.forwardRef(
9166
9166
  ({
9167
9167
  className,
9168
9168
  value,
@@ -9229,7 +9229,7 @@ var init_RangeSlider = __esm({
9229
9229
  md: "w-4 h-4",
9230
9230
  lg: "w-5 h-5"
9231
9231
  };
9232
- RangeSlider = React98__default.forwardRef(
9232
+ RangeSlider = React96__default.forwardRef(
9233
9233
  ({
9234
9234
  className,
9235
9235
  min = 0,
@@ -9737,7 +9737,7 @@ var init_ContentSection = __esm({
9737
9737
  md: "py-16",
9738
9738
  lg: "py-24"
9739
9739
  };
9740
- ContentSection = React98__default.forwardRef(
9740
+ ContentSection = React96__default.forwardRef(
9741
9741
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
9742
9742
  return /* @__PURE__ */ jsx(
9743
9743
  Box,
@@ -10271,7 +10271,7 @@ var init_AnimatedReveal = __esm({
10271
10271
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
10272
10272
  "none": {}
10273
10273
  };
10274
- AnimatedReveal = React98__default.forwardRef(
10274
+ AnimatedReveal = React96__default.forwardRef(
10275
10275
  ({
10276
10276
  trigger = "scroll",
10277
10277
  animation = "fade-up",
@@ -10431,7 +10431,7 @@ var init_AnimatedGraphic = __esm({
10431
10431
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
10432
10432
  "use client";
10433
10433
  init_cn();
10434
- AnimatedGraphic = React98__default.forwardRef(
10434
+ AnimatedGraphic = React96__default.forwardRef(
10435
10435
  ({
10436
10436
  src,
10437
10437
  svgContent,
@@ -10454,7 +10454,7 @@ var init_AnimatedGraphic = __esm({
10454
10454
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
10455
10455
  const resolvedSvg = svgContent ?? fetchedSvg;
10456
10456
  const prevAnimateRef = useRef(animate);
10457
- const setRef = React98__default.useCallback(
10457
+ const setRef = React96__default.useCallback(
10458
10458
  (node) => {
10459
10459
  containerRef.current = node;
10460
10460
  if (typeof ref === "function") ref(node);
@@ -10676,50 +10676,23 @@ function ScoreDisplay({
10676
10676
  icon,
10677
10677
  size = "md",
10678
10678
  className,
10679
- animated = true,
10680
10679
  locale = "en-US"
10681
10680
  }) {
10682
10681
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof score === "number" && !Number.isNaN(score) ? score : 0;
10683
- const [displayValue, setDisplayValue] = React98.useState(resolvedValue);
10684
- const [isAnimating, setIsAnimating] = React98.useState(false);
10685
- React98.useEffect(() => {
10686
- if (!animated || displayValue === resolvedValue) {
10687
- setDisplayValue(resolvedValue);
10688
- return;
10689
- }
10690
- setIsAnimating(true);
10691
- const diff = resolvedValue - displayValue;
10692
- const steps = Math.min(Math.abs(diff), 20);
10693
- const increment = diff / steps;
10694
- let current = displayValue;
10695
- let step = 0;
10696
- const timer = setInterval(() => {
10697
- step++;
10698
- current += increment;
10699
- setDisplayValue(Math.round(current));
10700
- if (step >= steps) {
10701
- clearInterval(timer);
10702
- setDisplayValue(resolvedValue);
10703
- setIsAnimating(false);
10704
- }
10705
- }, 50);
10706
- return () => clearInterval(timer);
10707
- }, [resolvedValue, animated]);
10708
- const formattedValue = new Intl.NumberFormat(locale).format(displayValue);
10682
+ const formattedValue = new Intl.NumberFormat(locale).format(resolvedValue);
10709
10683
  return /* @__PURE__ */ jsxs(
10710
10684
  "div",
10711
10685
  {
10712
10686
  className: cn(
10713
10687
  "flex items-center gap-2 font-bold",
10714
10688
  sizeMap2[size],
10715
- isAnimating && "animate-pulse",
10716
10689
  className
10717
10690
  ),
10718
10691
  children: [
10719
10692
  assetUrl ? /* @__PURE__ */ jsx(
10720
10693
  "img",
10721
10694
  {
10722
- src: assetUrl,
10695
+ src: assetUrl.url,
10723
10696
  alt: "",
10724
10697
  width: 20,
10725
10698
  height: 20,
@@ -10736,7 +10709,6 @@ function ScoreDisplay({
10736
10709
  var sizeMap2, DEFAULT_ASSET_URL;
10737
10710
  var init_ScoreDisplay = __esm({
10738
10711
  "components/game/atoms/ScoreDisplay.tsx"() {
10739
- "use client";
10740
10712
  init_cn();
10741
10713
  init_Icon();
10742
10714
  sizeMap2 = {
@@ -10745,7 +10717,11 @@ var init_ScoreDisplay = __esm({
10745
10717
  lg: "text-2xl",
10746
10718
  xl: "text-4xl"
10747
10719
  };
10748
- DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
10720
+ DEFAULT_ASSET_URL = {
10721
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
10722
+ role: "effect",
10723
+ category: "effect"
10724
+ };
10749
10725
  ScoreDisplay.displayName = "ScoreDisplay";
10750
10726
  }
10751
10727
  });
@@ -10765,9 +10741,9 @@ function ControlButton({
10765
10741
  className
10766
10742
  }) {
10767
10743
  const eventBus = useEventBus();
10768
- const [isPressed, setIsPressed] = React98.useState(false);
10744
+ const [isPressed, setIsPressed] = React96.useState(false);
10769
10745
  const actualPressed = pressed ?? isPressed;
10770
- const handlePointerDown = React98.useCallback(
10746
+ const handlePointerDown = React96.useCallback(
10771
10747
  (e) => {
10772
10748
  e.preventDefault();
10773
10749
  if (disabled) return;
@@ -10777,7 +10753,7 @@ function ControlButton({
10777
10753
  },
10778
10754
  [disabled, pressEvent, eventBus, onPress]
10779
10755
  );
10780
- const handlePointerUp = React98.useCallback(
10756
+ const handlePointerUp = React96.useCallback(
10781
10757
  (e) => {
10782
10758
  e.preventDefault();
10783
10759
  if (disabled) return;
@@ -10787,7 +10763,7 @@ function ControlButton({
10787
10763
  },
10788
10764
  [disabled, releaseEvent, eventBus, onRelease]
10789
10765
  );
10790
- const handlePointerLeave = React98.useCallback(
10766
+ const handlePointerLeave = React96.useCallback(
10791
10767
  (e) => {
10792
10768
  if (isPressed) {
10793
10769
  setIsPressed(false);
@@ -10821,7 +10797,7 @@ function ControlButton({
10821
10797
  children: assetUrl ? /* @__PURE__ */ jsx(
10822
10798
  "img",
10823
10799
  {
10824
- src: assetUrl,
10800
+ src: assetUrl.url,
10825
10801
  alt: "",
10826
10802
  width: 24,
10827
10803
  height: 24,
@@ -10861,7 +10837,11 @@ var init_ControlButton = __esm({
10861
10837
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
10862
10838
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
10863
10839
  };
10864
- DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
10840
+ DEFAULT_ASSET_URL2 = {
10841
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
10842
+ role: "effect",
10843
+ category: "effect"
10844
+ };
10865
10845
  ControlButton.displayName = "ControlButton";
10866
10846
  }
10867
10847
  });
@@ -10875,13 +10855,6 @@ var init_spriteSheetConstants = __esm({
10875
10855
  });
10876
10856
 
10877
10857
  // components/game/organisms/utils/spriteAnimation.ts
10878
- function inferDirection(dx, dy) {
10879
- if (dx === 0 && dy === 0) return "se";
10880
- if (dx >= 0 && dy >= 0) return "se";
10881
- if (dx <= 0 && dy >= 0) return "sw";
10882
- if (dx >= 0 && dy <= 0) return "ne";
10883
- return "nw";
10884
- }
10885
10858
  function resolveSheetDirection(facing) {
10886
10859
  switch (facing) {
10887
10860
  case "se":
@@ -10902,25 +10875,12 @@ function frameRect(frame, row, columns, frameWidth, frameHeight) {
10902
10875
  sh: frameHeight
10903
10876
  };
10904
10877
  }
10905
- function getCurrentFrameFromDef(def, elapsed) {
10906
- const frameDuration = 1e3 / def.frameRate;
10907
- const totalDuration = def.frames * frameDuration;
10908
- if (def.loop) {
10909
- const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
10910
- return { frame: frame2, finished: false };
10911
- }
10912
- if (elapsed >= totalDuration) {
10913
- return { frame: def.frames - 1, finished: true };
10914
- }
10915
- const frame = Math.floor(elapsed / frameDuration);
10916
- return { frame, finished: false };
10917
- }
10918
10878
  var init_spriteAnimation = __esm({
10919
10879
  "components/game/organisms/utils/spriteAnimation.ts"() {
10920
10880
  }
10921
10881
  });
10922
10882
  function Sprite({
10923
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
10883
+ spritesheet = DEFAULT_SPRITESHEET,
10924
10884
  frameWidth = 64,
10925
10885
  frameHeight = 64,
10926
10886
  frame = 0,
@@ -10933,6 +10893,8 @@ function Sprite({
10933
10893
  opacity = 1,
10934
10894
  zIndex = 0,
10935
10895
  columns = 16,
10896
+ animState: _animState,
10897
+ frameRate: _frameRate,
10936
10898
  className,
10937
10899
  onClick,
10938
10900
  action
@@ -10971,7 +10933,7 @@ function Sprite({
10971
10933
  position: "absolute",
10972
10934
  width: frameWidth,
10973
10935
  height: frameHeight,
10974
- backgroundImage: `url(${spritesheet})`,
10936
+ backgroundImage: `url(${spritesheet.url})`,
10975
10937
  backgroundPosition,
10976
10938
  backgroundRepeat: "no-repeat",
10977
10939
  imageRendering: "pixelated",
@@ -10984,11 +10946,17 @@ function Sprite({
10984
10946
  }
10985
10947
  );
10986
10948
  }
10949
+ var DEFAULT_SPRITESHEET;
10987
10950
  var init_Sprite = __esm({
10988
10951
  "components/game/atoms/Sprite.tsx"() {
10989
10952
  "use client";
10990
10953
  init_useEventBus();
10991
10954
  init_spriteAnimation();
10955
+ DEFAULT_SPRITESHEET = {
10956
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
10957
+ role: "tile",
10958
+ category: "tile"
10959
+ };
10992
10960
  }
10993
10961
  });
10994
10962
  function StateIndicator({
@@ -11018,7 +10986,7 @@ function StateIndicator({
11018
10986
  /* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsx(
11019
10987
  "img",
11020
10988
  {
11021
- src: assetUrl,
10989
+ src: assetUrl.url,
11022
10990
  alt: displayLabel,
11023
10991
  width: 16,
11024
10992
  height: 16,
@@ -11037,7 +11005,11 @@ var init_StateIndicator = __esm({
11037
11005
  init_Box();
11038
11006
  init_Icon();
11039
11007
  init_cn();
11040
- DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
11008
+ DEFAULT_ASSET_URL3 = {
11009
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11010
+ role: "effect",
11011
+ category: "item"
11012
+ };
11041
11013
  DEFAULT_STATE_STYLES = {
11042
11014
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
11043
11015
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -11135,7 +11107,7 @@ function ResourceCounter({
11135
11107
  assetUrl ? /* @__PURE__ */ jsx(
11136
11108
  "img",
11137
11109
  {
11138
- src: assetUrl,
11110
+ src: assetUrl.url,
11139
11111
  alt: label,
11140
11112
  width: sizes.img,
11141
11113
  height: sizes.img,
@@ -11168,7 +11140,11 @@ var init_ResourceCounter = __esm({
11168
11140
  error: "text-error",
11169
11141
  muted: "text-muted-foreground"
11170
11142
  };
11171
- DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
11143
+ DEFAULT_ASSET_URL4 = {
11144
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
11145
+ role: "effect",
11146
+ category: "world"
11147
+ };
11172
11148
  sizeMap5 = {
11173
11149
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
11174
11150
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -11214,7 +11190,7 @@ function ItemSlot({
11214
11190
  assetUrl ? /* @__PURE__ */ jsx(
11215
11191
  "img",
11216
11192
  {
11217
- src: assetUrl,
11193
+ src: assetUrl?.url,
11218
11194
  alt: label,
11219
11195
  width: px,
11220
11196
  height: px,
@@ -11262,7 +11238,11 @@ var init_ItemSlot = __esm({
11262
11238
  epic: "shadow-lg",
11263
11239
  legendary: "shadow-lg"
11264
11240
  };
11265
- DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
11241
+ DEFAULT_ASSET_URL5 = {
11242
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11243
+ role: "effect",
11244
+ category: "item"
11245
+ };
11266
11246
  assetSizeMap = {
11267
11247
  sm: 28,
11268
11248
  md: 40,
@@ -11308,7 +11288,7 @@ function TurnIndicator({
11308
11288
  assetUrl ? /* @__PURE__ */ jsx(
11309
11289
  "img",
11310
11290
  {
11311
- src: assetUrl,
11291
+ src: assetUrl.url,
11312
11292
  alt: "",
11313
11293
  width: 12,
11314
11294
  height: 12,
@@ -11331,7 +11311,11 @@ var init_TurnIndicator = __esm({
11331
11311
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
11332
11312
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
11333
11313
  };
11334
- DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
11314
+ DEFAULT_ASSET_URL6 = {
11315
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
11316
+ role: "effect",
11317
+ category: "effect"
11318
+ };
11335
11319
  TurnIndicator.displayName = "TurnIndicator";
11336
11320
  }
11337
11321
  });
@@ -11370,7 +11354,7 @@ function ComboCounter({
11370
11354
  assetUrl && /* @__PURE__ */ jsx(
11371
11355
  "img",
11372
11356
  {
11373
- src: assetUrl,
11357
+ src: assetUrl.url,
11374
11358
  alt: "combo",
11375
11359
  width: 24,
11376
11360
  height: 24,
@@ -11396,7 +11380,11 @@ var DEFAULT_ASSET_URL7, sizeMap8;
11396
11380
  var init_ComboCounter = __esm({
11397
11381
  "components/game/atoms/ComboCounter.tsx"() {
11398
11382
  init_cn();
11399
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
11383
+ DEFAULT_ASSET_URL7 = {
11384
+ url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
11385
+ role: "effect",
11386
+ category: "effect"
11387
+ };
11400
11388
  sizeMap8 = {
11401
11389
  sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
11402
11390
  md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
@@ -11416,21 +11404,6 @@ function XPBar({
11416
11404
  }) {
11417
11405
  const sizes = sizeMap9[size];
11418
11406
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
11419
- const [fillWidth, setFillWidth] = React98.useState(animated ? 0 : percentage);
11420
- React98.useEffect(() => {
11421
- if (!animated) {
11422
- setFillWidth(percentage);
11423
- return;
11424
- }
11425
- let frame2;
11426
- const frame1 = requestAnimationFrame(() => {
11427
- frame2 = requestAnimationFrame(() => setFillWidth(percentage));
11428
- });
11429
- return () => {
11430
- cancelAnimationFrame(frame1);
11431
- cancelAnimationFrame(frame2);
11432
- };
11433
- }, [animated, percentage]);
11434
11407
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), children: [
11435
11408
  level != null && /* @__PURE__ */ jsxs(
11436
11409
  "span",
@@ -11462,7 +11435,7 @@ function XPBar({
11462
11435
  "bg-gradient-to-r from-accent to-info",
11463
11436
  animated && "transition-all duration-500 ease-out"
11464
11437
  ),
11465
- style: { width: `${fillWidth}%` }
11438
+ style: { width: `${percentage}%` }
11466
11439
  }
11467
11440
  )
11468
11441
  }
@@ -11479,7 +11452,6 @@ function XPBar({
11479
11452
  var sizeMap9;
11480
11453
  var init_XPBar = __esm({
11481
11454
  "components/game/atoms/XPBar.tsx"() {
11482
- "use client";
11483
11455
  init_cn();
11484
11456
  sizeMap9 = {
11485
11457
  sm: { bar: "h-2", text: "text-xs", badge: "text-xs px-1.5 py-0.5" },
@@ -11532,7 +11504,7 @@ function WaypointMarker({
11532
11504
  children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(
11533
11505
  "img",
11534
11506
  {
11535
- src: assetUrl,
11507
+ src: assetUrl.url,
11536
11508
  alt: label,
11537
11509
  width: sizes.img,
11538
11510
  height: sizes.img,
@@ -11561,7 +11533,11 @@ var init_WaypointMarker = __esm({
11561
11533
  "components/game/atoms/WaypointMarker.tsx"() {
11562
11534
  init_cn();
11563
11535
  init_Icon();
11564
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
11536
+ DEFAULT_ASSET_URL8 = {
11537
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
11538
+ role: "effect",
11539
+ category: "world"
11540
+ };
11565
11541
  sizeMap10 = {
11566
11542
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
11567
11543
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -11602,7 +11578,7 @@ function StatusEffect({
11602
11578
  /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(
11603
11579
  "img",
11604
11580
  {
11605
- src: assetUrl,
11581
+ src: assetUrl.url,
11606
11582
  alt: label,
11607
11583
  width: sizes.img,
11608
11584
  height: sizes.img,
@@ -11641,7 +11617,11 @@ var init_StatusEffect = __esm({
11641
11617
  "components/game/atoms/StatusEffect.tsx"() {
11642
11618
  init_cn();
11643
11619
  init_Icon();
11644
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
11620
+ DEFAULT_ASSET_URL9 = {
11621
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
11622
+ role: "effect",
11623
+ category: "effect"
11624
+ };
11645
11625
  sizeMap11 = {
11646
11626
  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 },
11647
11627
  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 },
@@ -11679,7 +11659,7 @@ function DamageNumber({
11679
11659
  assetUrl && /* @__PURE__ */ jsx(
11680
11660
  "img",
11681
11661
  {
11682
- src: assetUrl,
11662
+ src: assetUrl.url,
11683
11663
  alt: "",
11684
11664
  width: 14,
11685
11665
  height: 14,
@@ -11715,14 +11695,18 @@ var init_DamageNumber = __esm({
11715
11695
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
11716
11696
  }
11717
11697
  `;
11718
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
11698
+ DEFAULT_ASSET_URL10 = {
11699
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
11700
+ role: "effect",
11701
+ category: "effect"
11702
+ };
11719
11703
  DamageNumber.displayName = "DamageNumber";
11720
11704
  }
11721
11705
  });
11722
11706
  function DialogueBubble({
11723
11707
  speaker = "Hero",
11724
11708
  text = "The dungeon awaits. Choose your path wisely.",
11725
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
11709
+ portrait = DEFAULT_PORTRAIT,
11726
11710
  position = "bottom",
11727
11711
  className
11728
11712
  }) {
@@ -11738,7 +11722,7 @@ function DialogueBubble({
11738
11722
  portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(
11739
11723
  "img",
11740
11724
  {
11741
- src: portrait,
11725
+ src: portrait?.url,
11742
11726
  alt: speaker ?? "speaker",
11743
11727
  className: "w-full h-full object-cover"
11744
11728
  }
@@ -11751,9 +11735,15 @@ function DialogueBubble({
11751
11735
  }
11752
11736
  );
11753
11737
  }
11738
+ var DEFAULT_PORTRAIT;
11754
11739
  var init_DialogueBubble = __esm({
11755
11740
  "components/game/atoms/DialogueBubble.tsx"() {
11756
11741
  init_cn();
11742
+ DEFAULT_PORTRAIT = {
11743
+ url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
11744
+ role: "effect",
11745
+ category: "character"
11746
+ };
11757
11747
  DialogueBubble.displayName = "DialogueBubble";
11758
11748
  }
11759
11749
  });
@@ -11797,7 +11787,7 @@ function ChoiceButton({
11797
11787
  assetUrl ? /* @__PURE__ */ jsx(
11798
11788
  "img",
11799
11789
  {
11800
- src: assetUrl,
11790
+ src: assetUrl.url,
11801
11791
  alt: "",
11802
11792
  width: 16,
11803
11793
  height: 16,
@@ -11867,7 +11857,7 @@ function ActionButton({
11867
11857
  assetUrl ? /* @__PURE__ */ jsx(
11868
11858
  "img",
11869
11859
  {
11870
- src: assetUrl,
11860
+ src: assetUrl.url,
11871
11861
  alt: "",
11872
11862
  width: 16,
11873
11863
  height: 16,
@@ -11911,7 +11901,11 @@ var init_ActionButton = __esm({
11911
11901
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
11912
11902
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
11913
11903
  };
11914
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
11904
+ DEFAULT_ASSET_URL11 = {
11905
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
11906
+ role: "effect",
11907
+ category: "effect"
11908
+ };
11915
11909
  ActionButton.displayName = "ActionButton";
11916
11910
  }
11917
11911
  });
@@ -11925,9 +11919,9 @@ function MiniMap({
11925
11919
  viewportRect = DEFAULT_VIEWPORT,
11926
11920
  className
11927
11921
  }) {
11928
- const canvasRef = React98.useRef(null);
11929
- const frameRef = React98.useRef(0);
11930
- React98.useEffect(() => {
11922
+ const canvasRef = React96.useRef(null);
11923
+ const frameRef = React96.useRef(0);
11924
+ React96.useEffect(() => {
11931
11925
  const canvas = canvasRef.current;
11932
11926
  if (!canvas) return;
11933
11927
  const ctx = canvas.getContext("2d");
@@ -12116,7 +12110,7 @@ var init_ErrorBoundary = __esm({
12116
12110
  }
12117
12111
  );
12118
12112
  };
12119
- ErrorBoundary = class extends React98__default.Component {
12113
+ ErrorBoundary = class extends React96__default.Component {
12120
12114
  constructor(props) {
12121
12115
  super(props);
12122
12116
  __publicField(this, "reset", () => {
@@ -12427,7 +12421,7 @@ var init_Container = __esm({
12427
12421
  as: Component2 = "div"
12428
12422
  }) => {
12429
12423
  const resolvedSize = maxWidth ?? size ?? "lg";
12430
- return React98__default.createElement(
12424
+ return React96__default.createElement(
12431
12425
  Component2,
12432
12426
  {
12433
12427
  className: cn(
@@ -13150,8 +13144,8 @@ function ActionButtons({
13150
13144
  disabled
13151
13145
  }) {
13152
13146
  const eventBus = useEventBus();
13153
- const [activeButtons, setActiveButtons] = React98.useState(/* @__PURE__ */ new Set());
13154
- const handlePress = React98.useCallback(
13147
+ const [activeButtons, setActiveButtons] = React96.useState(/* @__PURE__ */ new Set());
13148
+ const handlePress = React96.useCallback(
13155
13149
  (id) => {
13156
13150
  setActiveButtons((prev) => new Set(prev).add(id));
13157
13151
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -13159,7 +13153,7 @@ function ActionButtons({
13159
13153
  },
13160
13154
  [actionEvent, eventBus, onAction]
13161
13155
  );
13162
- const handleRelease = React98.useCallback(
13156
+ const handleRelease = React96.useCallback(
13163
13157
  (id) => {
13164
13158
  setActiveButtons((prev) => {
13165
13159
  const next = new Set(prev);
@@ -13989,50 +13983,6 @@ var init_AuthLayout = __esm({
13989
13983
  AuthLayout.displayName = "AuthLayout";
13990
13984
  }
13991
13985
  });
13992
- var LoadingState;
13993
- var init_LoadingState = __esm({
13994
- "components/core/molecules/LoadingState.tsx"() {
13995
- "use client";
13996
- init_cn();
13997
- init_atoms2();
13998
- init_Stack();
13999
- init_Typography();
14000
- LoadingState = ({
14001
- title,
14002
- message,
14003
- className
14004
- }) => {
14005
- const { t } = useTranslate();
14006
- const displayMessage = message ?? t("common.loading");
14007
- return /* @__PURE__ */ jsxs(
14008
- VStack,
14009
- {
14010
- align: "center",
14011
- className: cn(
14012
- "justify-center py-12",
14013
- className
14014
- ),
14015
- children: [
14016
- /* @__PURE__ */ jsx(Spinner, { size: "lg" }),
14017
- title && /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "mt-4 text-lg font-semibold text-foreground", children: title }),
14018
- /* @__PURE__ */ jsx(
14019
- Typography,
14020
- {
14021
- variant: "small",
14022
- className: cn(
14023
- "text-muted-foreground",
14024
- title ? "mt-2" : "mt-4"
14025
- ),
14026
- children: displayMessage
14027
- }
14028
- )
14029
- ]
14030
- }
14031
- );
14032
- };
14033
- LoadingState.displayName = "LoadingState";
14034
- }
14035
- });
14036
13986
  function getState() {
14037
13987
  if (typeof window !== "undefined") {
14038
13988
  const w = window;
@@ -14542,12 +14492,7 @@ var init_useCanvasGestures = __esm({
14542
14492
  }
14543
14493
  });
14544
14494
  function unitAtlasUrl(unit) {
14545
- if (unit.spriteSheet) return unit.spriteSheet;
14546
- const sprite = unit.sprite;
14547
- if (!sprite) return null;
14548
- const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
14549
- if (!match) return null;
14550
- return `${match[1]}.json`;
14495
+ return unit.spriteSheet?.url ?? null;
14551
14496
  }
14552
14497
  function resolveSheetUrl(atlasUrl, relativeSheetPath) {
14553
14498
  try {
@@ -14562,9 +14507,6 @@ function useUnitSpriteAtlas(units) {
14562
14507
  const loadingRef = useRef(/* @__PURE__ */ new Set());
14563
14508
  const [pendingCount, setPendingCount] = useState(0);
14564
14509
  const [, forceTick] = useState(0);
14565
- const animStatesRef = useRef(/* @__PURE__ */ new Map());
14566
- const lastTickRef = useRef(0);
14567
- const rafRef = useRef(0);
14568
14510
  const atlasUrls = useMemo(() => {
14569
14511
  const set = /* @__PURE__ */ new Set();
14570
14512
  for (const unit of units) {
@@ -14610,54 +14552,6 @@ function useUnitSpriteAtlas(units) {
14610
14552
  }
14611
14553
  return [...urls];
14612
14554
  }, [units, pendingCount]);
14613
- useEffect(() => {
14614
- const hasAtlasUnits = units.some((u) => unitAtlasUrl(u) !== null);
14615
- if (!hasAtlasUnits) return;
14616
- let running = true;
14617
- const tick = (ts) => {
14618
- if (!running) return;
14619
- const last = lastTickRef.current || ts;
14620
- const delta = ts - last;
14621
- lastTickRef.current = ts;
14622
- const states = animStatesRef.current;
14623
- const currentIds = /* @__PURE__ */ new Set();
14624
- for (const unit of units) {
14625
- if (unitAtlasUrl(unit) === null) continue;
14626
- currentIds.add(unit.id);
14627
- let state = states.get(unit.id);
14628
- if (!state) {
14629
- state = { animation: "idle", direction: "se", elapsed: 0, walkHold: 0, prev: null };
14630
- states.set(unit.id, state);
14631
- }
14632
- const posX = unit.position?.x ?? unit.x ?? 0;
14633
- const posY = unit.position?.y ?? unit.y ?? 0;
14634
- if (state.prev) {
14635
- const dx = posX - state.prev.x;
14636
- const dy = posY - state.prev.y;
14637
- if (dx !== 0 || dy !== 0) {
14638
- state.animation = "walk";
14639
- state.direction = inferDirection(dx, dy);
14640
- state.walkHold = WALK_HOLD_MS;
14641
- } else if (state.animation === "walk") {
14642
- state.walkHold -= delta;
14643
- if (state.walkHold <= 0) state.animation = "idle";
14644
- }
14645
- }
14646
- state.prev = { x: posX, y: posY };
14647
- state.elapsed += delta;
14648
- }
14649
- for (const id of states.keys()) {
14650
- if (!currentIds.has(id)) states.delete(id);
14651
- }
14652
- rafRef.current = requestAnimationFrame(tick);
14653
- };
14654
- rafRef.current = requestAnimationFrame(tick);
14655
- return () => {
14656
- running = false;
14657
- cancelAnimationFrame(rafRef.current);
14658
- lastTickRef.current = 0;
14659
- };
14660
- }, [units]);
14661
14555
  const resolveUnitFrame = useCallback((unitId) => {
14662
14556
  const unit = units.find((u) => u.id === unitId);
14663
14557
  if (!unit) return null;
@@ -14665,18 +14559,14 @@ function useUnitSpriteAtlas(units) {
14665
14559
  if (!atlasUrl) return null;
14666
14560
  const atlas = atlasCacheRef.current.get(atlasUrl);
14667
14561
  if (!atlas) return null;
14668
- const state = animStatesRef.current.get(unitId);
14669
- const animation = state?.animation ?? "idle";
14670
- const direction = state?.direction ?? "se";
14671
- const elapsed = state?.elapsed ?? 0;
14562
+ const animation = unit.animation ?? "idle";
14563
+ const frame = unit.frame ?? 0;
14672
14564
  const def = atlas.animations[animation] ?? atlas.animations.idle;
14673
14565
  if (!def) return null;
14674
- const { sheetDir, flipX } = resolveSheetDirection(direction);
14566
+ const { sheetDir, flipX } = resolveSheetDirection("se");
14675
14567
  const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
14676
14568
  if (!rel) return null;
14677
14569
  const sheetUrl = resolveSheetUrl(atlasUrl, rel);
14678
- const isIdle = animation === "idle";
14679
- const frame = isIdle ? 0 : getCurrentFrameFromDef(def, elapsed).frame;
14680
14570
  const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
14681
14571
  return {
14682
14572
  sheetUrl,
@@ -14685,17 +14575,15 @@ function useUnitSpriteAtlas(units) {
14685
14575
  sw: rect.sw,
14686
14576
  sh: rect.sh,
14687
14577
  flipX,
14688
- applyBreathing: isIdle
14578
+ applyBreathing: animation === "idle"
14689
14579
  };
14690
14580
  }, [units]);
14691
14581
  return { sheetUrls, resolveUnitFrame, pendingCount };
14692
14582
  }
14693
- var WALK_HOLD_MS;
14694
14583
  var init_useUnitSpriteAtlas = __esm({
14695
14584
  "components/game/molecules/useUnitSpriteAtlas.ts"() {
14696
14585
  "use client";
14697
14586
  init_spriteAnimation();
14698
- WALK_HOLD_MS = 600;
14699
14587
  }
14700
14588
  });
14701
14589
 
@@ -14763,6 +14651,7 @@ function IsometricCanvas({
14763
14651
  tiles: _tilesPropRaw = [],
14764
14652
  units: _unitsPropRaw = [],
14765
14653
  features: _featuresPropRaw = [],
14654
+ effects: _effectsPropRaw = [],
14766
14655
  // Interaction state
14767
14656
  selectedUnitId = null,
14768
14657
  validMoves = [],
@@ -14795,23 +14684,21 @@ function IsometricCanvas({
14795
14684
  resolveUnitFrame,
14796
14685
  effectSpriteUrls = [],
14797
14686
  onDrawEffects,
14798
- hasActiveEffects: hasActiveEffects2 = false,
14687
+ hasActiveEffects: _hasActiveEffects = false,
14799
14688
  // Tuning
14800
14689
  diamondTopY: diamondTopYProp,
14801
14690
  // Remote asset loading
14802
- assetBaseUrl,
14803
14691
  assetManifest
14804
14692
  }) {
14805
14693
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
14806
14694
  const unitsProp = Array.isArray(_unitsPropRaw) ? _unitsPropRaw : [];
14807
14695
  const featuresProp = Array.isArray(_featuresPropRaw) ? _featuresPropRaw : [];
14696
+ const effects = Array.isArray(_effectsPropRaw) ? _effectsPropRaw : [];
14808
14697
  const eventBus = useEventBus();
14809
14698
  const { t } = useTranslate();
14810
14699
  const canvasRef = useRef(null);
14811
14700
  const containerRef = useRef(null);
14812
- const minimapRef = useRef(null);
14813
- const animTimeRef = useRef(0);
14814
- const rafIdRef = useRef(0);
14701
+ const lerpRafRef = useRef(0);
14815
14702
  const [viewportSize, setViewportSize] = useState({ width: 800, height: 600 });
14816
14703
  useEffect(() => {
14817
14704
  const el = containerRef.current;
@@ -14835,7 +14722,7 @@ function IsometricCanvas({
14835
14722
  () => unitsProp.map((u) => u.position ? u : { ...u, position: { x: u.x ?? 0, y: u.y ?? 0 } }),
14836
14723
  [unitsProp]
14837
14724
  );
14838
- const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal, pendingCount: atlasPending } = useUnitSpriteAtlas(units);
14725
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal } = useUnitSpriteAtlas(units);
14839
14726
  const resolveFrameForUnit = useCallback((unitId) => {
14840
14727
  return resolveUnitFrame?.(unitId) ?? resolveUnitFrameInternal(unitId);
14841
14728
  }, [resolveUnitFrame, resolveUnitFrameInternal]);
@@ -14882,55 +14769,49 @@ function IsometricCanvas({
14882
14769
  const attackTargetSet = useMemo(() => {
14883
14770
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
14884
14771
  }, [attackTargets]);
14885
- const resolveManifestUrl7 = useCallback((relativePath) => {
14886
- if (!relativePath) return void 0;
14887
- if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
14888
- return relativePath;
14889
- }, [assetBaseUrl]);
14890
14772
  const spriteUrls = useMemo(() => {
14891
14773
  const urls = [];
14892
14774
  for (const tile of sortedTiles) {
14893
- if (tile.terrainSprite) urls.push(tile.terrainSprite);
14775
+ if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
14894
14776
  else if (getTerrainSprite) {
14895
14777
  const url = getTerrainSprite(tile.terrain ?? "");
14896
14778
  if (url) urls.push(url);
14897
14779
  } else {
14898
- const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14780
+ const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
14899
14781
  if (url) urls.push(url);
14900
14782
  }
14901
14783
  }
14902
14784
  for (const feature of features) {
14903
- if (feature.sprite) urls.push(feature.sprite);
14785
+ if (feature.sprite) urls.push(feature.sprite.url);
14904
14786
  else if (getFeatureSprite) {
14905
14787
  const url = getFeatureSprite(feature.type);
14906
14788
  if (url) urls.push(url);
14907
14789
  } else {
14908
- const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
14790
+ const url = assetManifest?.features?.[feature.type]?.url;
14909
14791
  if (url) urls.push(url);
14910
14792
  }
14911
14793
  }
14912
14794
  for (const unit of units) {
14913
- if (unit.sprite) urls.push(unit.sprite);
14795
+ if (unit.sprite) urls.push(unit.sprite.url);
14914
14796
  else if (getUnitSprite) {
14915
14797
  const url = getUnitSprite(unit);
14916
14798
  if (url) urls.push(url);
14917
14799
  } else if (unit.unitType) {
14918
- const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
14800
+ const url = assetManifest?.units?.[unit.unitType]?.url;
14919
14801
  if (url) urls.push(url);
14920
14802
  }
14921
14803
  }
14922
14804
  if (assetManifest?.effects) {
14923
- for (const path of Object.values(assetManifest.effects)) {
14924
- const url = resolveManifestUrl7(path);
14925
- if (url) urls.push(url);
14805
+ for (const asset of Object.values(assetManifest.effects)) {
14806
+ if (asset.url) urls.push(asset.url);
14926
14807
  }
14927
14808
  }
14928
14809
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
14929
14810
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
14930
14811
  if (backgroundImage) urls.push(backgroundImage);
14931
14812
  return [...new Set(urls.filter(Boolean))];
14932
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
14933
- const { getImage, pendingCount } = useImageCache(spriteUrls);
14813
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest]);
14814
+ const { getImage, pendingCount: _imagePendingCount } = useImageCache(spriteUrls);
14934
14815
  useEffect(() => {
14935
14816
  if (typeof window === "undefined") return;
14936
14817
  const canvas = canvasRef.current;
@@ -14954,71 +14835,34 @@ function IsometricCanvas({
14954
14835
  lerpToTarget
14955
14836
  } = useCamera();
14956
14837
  const resolveTerrainSpriteUrl = useCallback((tile) => {
14957
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14958
- }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
14838
+ return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
14839
+ }, [getTerrainSprite, assetManifest]);
14959
14840
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
14960
- return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
14961
- }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
14841
+ return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
14842
+ }, [getFeatureSprite, assetManifest]);
14962
14843
  const resolveUnitSpriteUrl = useCallback((unit) => {
14963
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
14964
- }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
14965
- const drawMinimap = useCallback(() => {
14966
- if (!showMinimap) return;
14967
- const miniCanvas = minimapRef.current;
14968
- if (!miniCanvas || sortedTiles.length === 0) return;
14969
- const mCtx = miniCanvas.getContext("2d");
14970
- if (!mCtx) return;
14971
- const mW = 150;
14972
- const mH = 100;
14973
- miniCanvas.width = mW;
14974
- miniCanvas.height = mH;
14975
- mCtx.clearRect(0, 0, mW, mH);
14976
- const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
14977
- const minX = Math.min(...allScreenPos.map((p2) => p2.x));
14978
- const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
14979
- const minY = Math.min(...allScreenPos.map((p2) => p2.y));
14980
- const tileBottomExtent = tileLayout === "hex" || tileLayout === "flat" ? scaledTileWidth : scaledTileHeight;
14981
- const maxY = Math.max(...allScreenPos.map((p2) => p2.y + tileBottomExtent));
14982
- const worldW = maxX - minX;
14983
- const worldH = maxY - minY;
14984
- const scaleM = Math.min(mW / worldW, mH / worldH) * 0.9;
14985
- const offsetMx = (mW - worldW * scaleM) / 2;
14986
- const offsetMy = (mH - worldH * scaleM) / 2;
14987
- for (const tile of sortedTiles) {
14988
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
14989
- const mx = (pos.x - minX) * scaleM + offsetMx;
14990
- const my = (pos.y - minY) * scaleM + offsetMy;
14991
- const mTileW = scaledTileWidth * scaleM;
14992
- const mFloorH = scaledFloorHeight * scaleM;
14993
- mCtx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : "#4ade80";
14994
- mCtx.beginPath();
14995
- mCtx.moveTo(mx + mTileW / 2, my);
14996
- mCtx.lineTo(mx + mTileW, my + mFloorH / 2);
14997
- mCtx.lineTo(mx + mTileW / 2, my + mFloorH);
14998
- mCtx.lineTo(mx, my + mFloorH / 2);
14999
- mCtx.closePath();
15000
- mCtx.fill();
15001
- }
15002
- for (const unit of units) {
15003
- if (!unit.position) continue;
15004
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
15005
- const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
15006
- const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
15007
- mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
15008
- mCtx.beginPath();
15009
- mCtx.arc(mx, my, 3, 0, Math.PI * 2);
15010
- mCtx.fill();
15011
- }
15012
- const cam = cameraRef.current;
15013
- const vLeft = (cam.x - minX) * scaleM + offsetMx;
15014
- const vTop = (cam.y - minY) * scaleM + offsetMy;
15015
- const vW = viewportSize.width / cam.zoom * scaleM;
15016
- const vH = viewportSize.height / cam.zoom * scaleM;
15017
- mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
15018
- mCtx.lineWidth = 1;
15019
- mCtx.strokeRect(vLeft, vTop, vW, vH);
15020
- }, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
15021
- const draw = useCallback((animTime) => {
14844
+ return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
14845
+ }, [getUnitSprite, assetManifest]);
14846
+ const miniMapTiles = useMemo(() => {
14847
+ if (!showMinimap) return [];
14848
+ return sortedTiles.map((t2) => ({
14849
+ x: t2.x,
14850
+ y: t2.y,
14851
+ color: t2.terrain === "water" ? "#3b82f6" : t2.terrain === "mountain" ? "#78716c" : "#4ade80"
14852
+ }));
14853
+ }, [showMinimap, sortedTiles]);
14854
+ const miniMapUnits = useMemo(() => {
14855
+ if (!showMinimap) return [];
14856
+ return units.filter((u) => u.position).map((u) => ({
14857
+ x: u.position.x,
14858
+ y: u.position.y,
14859
+ color: u.team === "player" ? "#60a5fa" : u.team === "enemy" ? "#f87171" : "#9ca3af",
14860
+ isPlayer: u.team === "player"
14861
+ }));
14862
+ }, [showMinimap, units]);
14863
+ const miniMapWidth = gridWidth || 10;
14864
+ const miniMapHeight = gridHeight || 10;
14865
+ const draw = useCallback(() => {
15022
14866
  const canvas = canvasRef.current;
15023
14867
  if (!canvas) return;
15024
14868
  const ctx = canvas.getContext("2d");
@@ -15104,8 +14948,7 @@ function IsometricCanvas({
15104
14948
  if (validMoveSet.has(tileKey)) {
15105
14949
  const centerX = pos.x + scaledTileWidth / 2;
15106
14950
  const topY = pos.y + scaledDiamondTopY;
15107
- const pulse = 0.15 + 0.1 * Math.sin(animTime * 4e-3);
15108
- ctx.fillStyle = `rgba(74, 222, 128, ${pulse})`;
14951
+ ctx.fillStyle = "rgba(74, 222, 128, 0.25)";
15109
14952
  ctx.beginPath();
15110
14953
  ctx.moveTo(centerX, topY);
15111
14954
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -15117,8 +14960,7 @@ function IsometricCanvas({
15117
14960
  if (attackTargetSet.has(tileKey)) {
15118
14961
  const centerX = pos.x + scaledTileWidth / 2;
15119
14962
  const topY = pos.y + scaledDiamondTopY;
15120
- const pulse = 0.2 + 0.15 * Math.sin(animTime * 5e-3);
15121
- ctx.fillStyle = `rgba(239, 68, 68, ${pulse})`;
14963
+ ctx.fillStyle = "rgba(239, 68, 68, 0.35)";
15122
14964
  ctx.beginPath();
15123
14965
  ctx.moveTo(centerX, topY);
15124
14966
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -15147,7 +14989,7 @@ function IsometricCanvas({
15147
14989
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
15148
14990
  continue;
15149
14991
  }
15150
- const spriteUrl = feature.sprite || resolveFeatureSpriteUrl(feature.type);
14992
+ const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
15151
14993
  const img = spriteUrl ? getImage(spriteUrl) : null;
15152
14994
  const centerX = pos.x + scaledTileWidth / 2;
15153
14995
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
@@ -15191,17 +15033,17 @@ function IsometricCanvas({
15191
15033
  const isSelected = unit.id === selectedUnitId;
15192
15034
  const centerX = pos.x + scaledTileWidth / 2;
15193
15035
  const groundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
15194
- const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
15036
+ const breatheOffset = 0;
15195
15037
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
15196
15038
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
15197
15039
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
15198
15040
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
15041
+ const unitIsSheet = unit.sprite?.dimension === "2d" && (unit.sprite?.animations?.length ?? 0) > 0;
15199
15042
  const SHEET_ROWS = 5;
15200
15043
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
15201
15044
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
15202
- const imgIsSheet = img ? img.naturalWidth % SHEET_COLUMNS === 0 && img.naturalHeight % SHEET_ROWS === 0 && Math.abs(sheetFrameW - sheetFrameH) < 2 : false;
15203
- const frameW = imgIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
15204
- const frameH = imgIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
15045
+ const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
15046
+ const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
15205
15047
  const ar = frameW / (frameH || 1);
15206
15048
  let drawH = unitDrawH;
15207
15049
  let drawW = unitDrawH * ar;
@@ -15216,7 +15058,7 @@ function IsometricCanvas({
15216
15058
  ctx.save();
15217
15059
  ctx.globalAlpha = 0.25;
15218
15060
  if (img) {
15219
- if (imgIsSheet) {
15061
+ if (unitIsSheet) {
15220
15062
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
15221
15063
  } else {
15222
15064
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
@@ -15231,10 +15073,9 @@ function IsometricCanvas({
15231
15073
  ctx.restore();
15232
15074
  }
15233
15075
  if (isSelected) {
15234
- const ringAlpha = 0.6 + 0.3 * Math.sin(animTime * 4e-3);
15235
15076
  ctx.beginPath();
15236
15077
  ctx.ellipse(centerX, groundY, drawW / 2 + 4 * scale, 12 * scale, 0, 0, Math.PI * 2);
15237
- ctx.strokeStyle = `rgba(0, 200, 255, ${ringAlpha})`;
15078
+ ctx.strokeStyle = "rgba(0, 200, 255, 0.8)";
15238
15079
  ctx.lineWidth = 3;
15239
15080
  ctx.stroke();
15240
15081
  }
@@ -15265,7 +15106,7 @@ function IsometricCanvas({
15265
15106
  } else if (img) {
15266
15107
  const spriteY = groundY - drawH - breatheOffset;
15267
15108
  const drawUnit = (x) => {
15268
- if (imgIsSheet) {
15109
+ if (unitIsSheet) {
15269
15110
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
15270
15111
  } else {
15271
15112
  ctx.drawImage(img, x, spriteY, drawW, drawH);
@@ -15290,66 +15131,29 @@ function IsometricCanvas({
15290
15131
  ctx.lineWidth = 2;
15291
15132
  ctx.stroke();
15292
15133
  }
15293
- if (unit.name) {
15294
- 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)";
15295
- ctx.font = `bold ${10 * scale * 2.5}px system-ui`;
15296
- ctx.textAlign = "center";
15297
- const textWidth = ctx.measureText(unit.name).width;
15298
- const labelY = groundY + 14 * scale - breatheOffset;
15299
- ctx.fillStyle = labelBg;
15300
- ctx.beginPath();
15301
- ctx.roundRect(centerX - textWidth / 2 - 6 * scale, labelY - 8 * scale, textWidth + 12 * scale, 16 * scale, 4 * scale);
15302
- ctx.fill();
15303
- ctx.fillStyle = "white";
15304
- ctx.fillText(unit.name, centerX, labelY + 4 * scale);
15305
- }
15306
- if (unit.health !== void 0 && unit.maxHealth !== void 0) {
15307
- const barWidth = 40 * scale;
15308
- const barHeight = 6 * scale;
15309
- const barX = centerX - barWidth / 2;
15310
- const barY = groundY - drawH - 2 * scale - breatheOffset;
15311
- const healthRatio = unit.health / unit.maxHealth;
15312
- const barRadius = barHeight / 2;
15313
- ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
15314
- ctx.beginPath();
15315
- ctx.roundRect(barX, barY, barWidth, barHeight, barRadius);
15316
- ctx.fill();
15317
- if (healthRatio > 0) {
15318
- const fillWidth = barWidth * healthRatio;
15319
- const gradient = ctx.createLinearGradient(barX, barY, barX, barY + barHeight);
15320
- if (healthRatio > 0.6) {
15321
- gradient.addColorStop(0, "#4ade80");
15322
- gradient.addColorStop(1, "#22c55e");
15323
- } else if (healthRatio > 0.3) {
15324
- gradient.addColorStop(0, "#fde047");
15325
- gradient.addColorStop(1, "#eab308");
15326
- } else {
15327
- gradient.addColorStop(0, "#f87171");
15328
- gradient.addColorStop(1, "#ef4444");
15329
- }
15330
- ctx.fillStyle = gradient;
15331
- ctx.save();
15332
- ctx.beginPath();
15333
- ctx.roundRect(barX, barY, fillWidth, barHeight, barRadius);
15334
- ctx.clip();
15335
- ctx.fillRect(barX, barY, fillWidth, barHeight);
15336
- ctx.restore();
15337
- }
15338
- ctx.strokeStyle = "rgba(255, 255, 255, 0.3)";
15339
- ctx.lineWidth = 1;
15340
- ctx.beginPath();
15341
- ctx.roundRect(barX, barY, barWidth, barHeight, barRadius);
15342
- ctx.stroke();
15343
- }
15344
15134
  }
15345
- onDrawEffects?.(ctx, animTime, getImage);
15135
+ for (const fx of effects) {
15136
+ const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
15137
+ if (!spriteUrl) continue;
15138
+ const img = getImage(spriteUrl);
15139
+ if (!img) continue;
15140
+ const pos = isoToScreen(fx.x, fx.y, scale, baseOffsetX, tileLayout);
15141
+ const cx = pos.x + scaledTileWidth / 2;
15142
+ const cy = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
15143
+ const alpha = Math.min(1, fx.ttl / 4);
15144
+ const prev = ctx.globalAlpha;
15145
+ ctx.globalAlpha = alpha;
15146
+ ctx.drawImage(img, cx - img.naturalWidth / 2, cy - img.naturalHeight / 2);
15147
+ ctx.globalAlpha = prev;
15148
+ }
15149
+ onDrawEffects?.(ctx, 0, getImage);
15346
15150
  ctx.restore();
15347
- drawMinimap();
15348
15151
  }, [
15349
15152
  sortedTiles,
15350
15153
  units,
15351
15154
  features,
15352
15155
  selectedUnitId,
15156
+ effects,
15353
15157
  tileLayout,
15354
15158
  scale,
15355
15159
  debug2,
@@ -15369,11 +15173,11 @@ function IsometricCanvas({
15369
15173
  attackTargetSet,
15370
15174
  hoveredTile,
15371
15175
  viewportSize,
15372
- drawMinimap,
15373
15176
  onDrawEffects,
15374
15177
  backgroundImage,
15375
15178
  cameraRef,
15376
- unitScale
15179
+ unitScale,
15180
+ assetManifest
15377
15181
  ]);
15378
15182
  useEffect(() => {
15379
15183
  if (!selectedUnitId) return;
@@ -15388,30 +15192,33 @@ function IsometricCanvas({
15388
15192
  };
15389
15193
  }, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
15390
15194
  useEffect(() => {
15391
- const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
15392
- draw(animTimeRef.current);
15393
- if (!hasAnimations) return;
15195
+ draw();
15196
+ }, [draw]);
15197
+ useEffect(() => {
15198
+ draw();
15199
+ }, [_imagePendingCount]);
15200
+ useEffect(() => {
15201
+ if (selectedUnitId == null) return;
15394
15202
  let running = true;
15395
- const animate = (timestamp) => {
15203
+ const tick = () => {
15396
15204
  if (!running) return;
15397
- animTimeRef.current = timestamp;
15398
- lerpToTarget();
15399
- draw(timestamp);
15400
- rafIdRef.current = requestAnimationFrame(animate);
15205
+ const stillLerping = lerpToTarget();
15206
+ draw();
15207
+ if (stillLerping) lerpRafRef.current = requestAnimationFrame(tick);
15401
15208
  };
15402
- rafIdRef.current = requestAnimationFrame(animate);
15209
+ lerpRafRef.current = requestAnimationFrame(tick);
15403
15210
  return () => {
15404
15211
  running = false;
15405
- cancelAnimationFrame(rafIdRef.current);
15212
+ cancelAnimationFrame(lerpRafRef.current);
15406
15213
  };
15407
- }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
15214
+ }, [selectedUnitId, lerpToTarget, draw]);
15408
15215
  const singlePointerActiveRef = useRef(false);
15409
15216
  const handleCanvasPointerDown = useCallback((e) => {
15410
15217
  singlePointerActiveRef.current = true;
15411
15218
  if (enableCamera) handlePointerDown(e);
15412
15219
  }, [enableCamera, handlePointerDown]);
15413
15220
  const handleCanvasPointerMove = useCallback((e) => {
15414
- if (enableCamera) handlePointerMove(e, () => draw(animTimeRef.current));
15221
+ if (enableCamera) handlePointerMove(e, () => draw());
15415
15222
  }, [enableCamera, handlePointerMove, draw]);
15416
15223
  const handleCanvasHover = useCallback((e) => {
15417
15224
  if (singlePointerActiveRef.current) return;
@@ -15453,10 +15260,10 @@ function IsometricCanvas({
15453
15260
  onTileLeave?.();
15454
15261
  }, [handleMouseLeave, onTileLeave, tileLeaveEvent, eventBus]);
15455
15262
  const applyZoom = useCallback((factor, centerX, centerY) => {
15456
- if (enableCamera) zoomAtPoint(factor, centerX, centerY, viewportSize, () => draw(animTimeRef.current));
15263
+ if (enableCamera) zoomAtPoint(factor, centerX, centerY, viewportSize, () => draw());
15457
15264
  }, [enableCamera, zoomAtPoint, viewportSize, draw]);
15458
15265
  const applyPanDelta = useCallback((dx, dy) => {
15459
- if (enableCamera) panBy(dx, dy, () => draw(animTimeRef.current));
15266
+ if (enableCamera) panBy(dx, dy, () => draw());
15460
15267
  }, [enableCamera, panBy, draw]);
15461
15268
  const cancelSinglePointer = useCallback(() => {
15462
15269
  singlePointerActiveRef.current = false;
@@ -15472,11 +15279,27 @@ function IsometricCanvas({
15472
15279
  onPanDelta: applyPanDelta,
15473
15280
  onMultiTouchStart: cancelSinglePointer
15474
15281
  });
15282
+ const unitOverlays = useMemo(() => {
15283
+ if (sortedTiles.length === 0) return [];
15284
+ return units.filter((u) => !!u.position).map((u) => {
15285
+ const pos = isoToScreen(u.position.x, u.position.y, scale, baseOffsetX, tileLayout);
15286
+ const cam = cameraRef.current;
15287
+ const screenX = (pos.x + scaledTileWidth / 2 - (cam.x + viewportSize.width / 2)) * cam.zoom + viewportSize.width / 2;
15288
+ const screenY = (pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5 - (cam.y + viewportSize.height / 2)) * cam.zoom + viewportSize.height / 2;
15289
+ return { unit: u, screenX, screenY };
15290
+ });
15291
+ }, [units, sortedTiles.length, scale, baseOffsetX, tileLayout, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, cameraRef]);
15475
15292
  if (error) {
15476
- return /* @__PURE__ */ jsx(ErrorState, { title: t("canvas.errorTitle"), message: error.message, className });
15293
+ 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: [
15294
+ /* @__PURE__ */ jsx(Icon, { name: "alert-circle", size: "xl" }),
15295
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-error", children: error.message })
15296
+ ] }) });
15477
15297
  }
15478
15298
  if (isLoading) {
15479
- return /* @__PURE__ */ jsx(LoadingState, { className });
15299
+ 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: [
15300
+ /* @__PURE__ */ jsx(Icon, { name: "loader", size: "xl", className: "animate-spin" }),
15301
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-muted-foreground", children: t("canvas.loadingMessage") || "Loading\u2026" })
15302
+ ] }) });
15480
15303
  }
15481
15304
  if (sortedTiles.length === 0) {
15482
15305
  return /* @__PURE__ */ jsx(
@@ -15541,14 +15364,36 @@ function IsometricCanvas({
15541
15364
  }
15542
15365
  )
15543
15366
  ] }),
15544
- showMinimap && /* @__PURE__ */ jsx(
15545
- "canvas",
15367
+ unitOverlays.map(({ unit, screenX, screenY }) => /* @__PURE__ */ jsxs(
15368
+ "div",
15369
+ {
15370
+ className: "absolute pointer-events-none",
15371
+ style: { left: Math.round(screenX), top: Math.round(screenY), transform: "translate(-50%, 0)", zIndex: 5 },
15372
+ children: [
15373
+ unit.name && /* @__PURE__ */ jsx(
15374
+ "div",
15375
+ {
15376
+ className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap",
15377
+ 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)" },
15378
+ children: unit.name
15379
+ }
15380
+ ),
15381
+ unit.health !== void 0 && unit.maxHealth !== void 0 && unit.maxHealth > 0 && /* @__PURE__ */ jsx(HealthBar, { current: unit.health, max: unit.maxHealth, format: "bar", size: "sm" })
15382
+ ]
15383
+ },
15384
+ unit.id
15385
+ )),
15386
+ showMinimap && /* @__PURE__ */ jsx("div", { className: "absolute bottom-2 right-2 pointer-events-none", style: { zIndex: 10 }, children: /* @__PURE__ */ jsx(
15387
+ MiniMap,
15546
15388
  {
15547
- ref: minimapRef,
15548
- className: "absolute bottom-2 right-2 border border-border rounded bg-background/80 pointer-events-none",
15549
- style: { width: 150, height: 100, zIndex: 10 }
15389
+ tiles: miniMapTiles,
15390
+ units: miniMapUnits,
15391
+ width: 150,
15392
+ height: 100,
15393
+ mapWidth: miniMapWidth,
15394
+ mapHeight: miniMapHeight
15550
15395
  }
15551
- )
15396
+ ) })
15552
15397
  ]
15553
15398
  }
15554
15399
  );
@@ -15563,8 +15408,8 @@ var init_IsometricCanvas = __esm({
15563
15408
  init_Stack();
15564
15409
  init_Icon();
15565
15410
  init_Typography();
15566
- init_LoadingState();
15567
- init_ErrorState();
15411
+ init_MiniMap();
15412
+ init_HealthBar();
15568
15413
  init_useImageCache();
15569
15414
  init_useCamera();
15570
15415
  init_useCanvasGestures();
@@ -15609,6 +15454,42 @@ var init_boardEntity = __esm({
15609
15454
  "components/game/organisms/boardEntity.ts"() {
15610
15455
  }
15611
15456
  });
15457
+
15458
+ // components/game/organisms/utils/makeAsset.ts
15459
+ function makeAsset(url, role, overrides = {}) {
15460
+ const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
15461
+ return {
15462
+ url,
15463
+ role,
15464
+ category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
15465
+ ...defaults,
15466
+ ...overrides
15467
+ };
15468
+ }
15469
+ function makeAssetMap(record, role, overrides = {}) {
15470
+ const result = {};
15471
+ for (const [key, url] of Object.entries(record)) {
15472
+ result[key] = makeAsset(url, role, overrides);
15473
+ }
15474
+ return result;
15475
+ }
15476
+ var ROLE_DEFAULTS;
15477
+ var init_makeAsset = __esm({
15478
+ "components/game/organisms/utils/makeAsset.ts"() {
15479
+ ROLE_DEFAULTS = {
15480
+ tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15481
+ decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15482
+ effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15483
+ item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
15484
+ player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15485
+ enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15486
+ npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15487
+ projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15488
+ vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
15489
+ ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
15490
+ };
15491
+ }
15492
+ });
15612
15493
  function buildDefaultBattleTiles() {
15613
15494
  const tiles = [];
15614
15495
  for (let y = 0; y < BATTLE_GRID_H; y++) {
@@ -15667,14 +15548,14 @@ function BattleBoard({
15667
15548
  if (o === null || typeof o.x !== "number" || typeof o.y !== "number") return [];
15668
15549
  const tile = { x: o.x, y: o.y };
15669
15550
  if (typeof o.terrain === "string") tile.terrain = o.terrain;
15670
- if (typeof o.terrainSprite === "string") tile.terrainSprite = o.terrainSprite;
15551
+ if (typeof o.terrainSprite === "string") tile.terrainSprite = makeAsset(o.terrainSprite, "tile");
15671
15552
  if (typeof o.passable === "boolean") tile.passable = o.passable;
15672
15553
  if (typeof o.movementCost === "number") tile.movementCost = o.movementCost;
15673
15554
  if (typeof o.elevation === "number") tile.elevation = o.elevation;
15674
15555
  if (typeof o.type === "string") tile.type = o.type;
15675
15556
  if (typeof o.tileType === "string") tile.tileType = o.tileType;
15676
15557
  if (typeof o.id === "string") tile.id = o.id;
15677
- if (typeof o.modelUrl === "string") tile.modelUrl = o.modelUrl;
15558
+ if (typeof o.modelUrl === "string") tile.modelUrl = makeAsset(o.modelUrl, "decoration", { dimension: "3d" });
15678
15559
  return [tile];
15679
15560
  }) : []);
15680
15561
  const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
@@ -15683,10 +15564,10 @@ function BattleBoard({
15683
15564
  if (o === null || typeof o.type !== "string" || typeof o.x !== "number" || typeof o.y !== "number") return [];
15684
15565
  const feat = { type: o.type, x: o.x, y: o.y };
15685
15566
  if (typeof o.id === "string") feat.id = o.id;
15686
- if (typeof o.sprite === "string") feat.sprite = o.sprite;
15567
+ if (typeof o.sprite === "string") feat.sprite = makeAsset(o.sprite, "decoration");
15687
15568
  if (typeof o.color === "string") feat.color = o.color;
15688
15569
  if (typeof o.elevation === "number") feat.elevation = o.elevation;
15689
- if (typeof o.assetUrl === "string") feat.assetUrl = o.assetUrl;
15570
+ if (typeof o.assetUrl === "string") feat.assetUrl = makeAsset(o.assetUrl, "decoration", { dimension: "3d" });
15690
15571
  return [feat];
15691
15572
  }) : []);
15692
15573
  const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
@@ -15802,7 +15683,7 @@ function BattleBoard({
15802
15683
  maxHealth: num(unit.maxHealth),
15803
15684
  unitType: unit.unitType == null ? void 0 : str(unit.unitType),
15804
15685
  heroId: unit.heroId == null ? void 0 : str(unit.heroId),
15805
- sprite: unit.sprite == null ? void 0 : str(unit.sprite),
15686
+ sprite: unit.sprite == null ? void 0 : makeAsset(str(unit.sprite), "npc"),
15806
15687
  traits: unitTraits?.map((tr) => ({
15807
15688
  name: tr.name,
15808
15689
  currentState: tr.currentState,
@@ -15952,7 +15833,6 @@ function BattleBoard({
15952
15833
  onTileHover: (x, y) => setHoveredTile({ x, y }),
15953
15834
  onTileLeave: () => setHoveredTile(null),
15954
15835
  scale,
15955
- assetBaseUrl: assetManifest?.baseUrl,
15956
15836
  assetManifest,
15957
15837
  backgroundImage,
15958
15838
  onDrawEffects,
@@ -16030,15 +15910,16 @@ var init_BattleBoard = __esm({
16030
15910
  init_IsometricCanvas();
16031
15911
  init_boardEntity();
16032
15912
  init_isometric();
15913
+ init_makeAsset();
16033
15914
  BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
16034
15915
  BATTLE_GRID_W = 16;
16035
15916
  BATTLE_GRID_H = 16;
16036
15917
  BATTLE_TERRAIN_SPRITES = [
16037
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
16038
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
16039
- `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
16040
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
16041
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
15918
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`, "tile"),
15919
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile"),
15920
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`, "tile"),
15921
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, "tile"),
15922
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile")
16042
15923
  ];
16043
15924
  DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
16044
15925
  BattleBoard.displayName = "BattleBoard";
@@ -16077,61 +15958,64 @@ function BattleTemplate({
16077
15958
  }
16078
15959
  );
16079
15960
  }
16080
- var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
15961
+ var CDN, STONE, DIRT, GRASS, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
16081
15962
  var init_BattleTemplate = __esm({
16082
15963
  "components/game/templates/BattleTemplate.tsx"() {
16083
15964
  init_BattleBoard();
15965
+ init_makeAsset();
16084
15966
  CDN = "https://almadar-kflow-assets.web.app/shared";
15967
+ STONE = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`, "tile");
15968
+ DIRT = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`, "tile");
15969
+ GRASS = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`, "tile");
16085
15970
  DEFAULT_BATTLE_TILES2 = [
16086
- { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16087
- { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16088
- { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16089
- { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16090
- { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16091
- { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16092
- { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
16093
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
16094
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
16095
- { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16096
- { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16097
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
16098
- { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
16099
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
16100
- { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16101
- { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16102
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
16103
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
16104
- { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
16105
- { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16106
- { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16107
- { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16108
- { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16109
- { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
16110
- { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` }
15971
+ { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15972
+ { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15973
+ { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15974
+ { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15975
+ { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15976
+ { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
15977
+ { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: DIRT },
15978
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
15979
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
15980
+ { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
15981
+ { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
15982
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
15983
+ { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: DIRT },
15984
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
15985
+ { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
15986
+ { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
15987
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
15988
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
15989
+ { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: DIRT },
15990
+ { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
15991
+ { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15992
+ { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15993
+ { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15994
+ { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15995
+ { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: STONE }
16111
15996
  ];
16112
15997
  DEFAULT_BATTLE_UNITS = [
16113
- { 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` },
16114
- { 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` }
15998
+ { 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") },
15999
+ { 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") }
16115
16000
  ];
16116
16001
  DEFAULT_BATTLE_FEATURES = [
16117
- { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: `${CDN}/world-map/gold_mine.png` },
16118
- { id: "f2", x: 3, y: 1, type: "portal", sprite: `${CDN}/world-map/portal_open.png` }
16002
+ { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: makeAsset(`${CDN}/world-map/gold_mine.png`, "decoration") },
16003
+ { id: "f2", x: 3, y: 1, type: "portal", sprite: makeAsset(`${CDN}/world-map/portal_open.png`, "decoration") }
16119
16004
  ];
16120
16005
  DEFAULT_BATTLE_MANIFEST = {
16121
- baseUrl: CDN,
16122
- terrains: {
16123
- stone: "/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png",
16124
- dirt: "/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png",
16125
- grass: "/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png"
16126
- },
16127
- units: {
16128
- worker: "/sprite-sheets/amir-sprite-sheet-se.png",
16129
- guardian: "/sprite-sheets/destroyer-sprite-sheet-sw.png"
16130
- },
16131
- features: {
16132
- gold_mine: "/world-map/gold_mine.png",
16133
- portal: "/world-map/portal_open.png"
16134
- }
16006
+ terrains: makeAssetMap({
16007
+ stone: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`,
16008
+ dirt: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`,
16009
+ grass: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`
16010
+ }, "tile"),
16011
+ units: makeAssetMap({
16012
+ worker: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png`,
16013
+ guardian: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`
16014
+ }, "npc"),
16015
+ features: makeAssetMap({
16016
+ gold_mine: `${CDN}/world-map/gold_mine.png`,
16017
+ portal: `${CDN}/world-map/portal_open.png`
16018
+ }, "decoration")
16135
16019
  };
16136
16020
  BattleTemplate.displayName = "BattleTemplate";
16137
16021
  }
@@ -16295,6 +16179,50 @@ var init_Tabs = __esm({
16295
16179
  Tabs.displayName = "Tabs";
16296
16180
  }
16297
16181
  });
16182
+ var LoadingState;
16183
+ var init_LoadingState = __esm({
16184
+ "components/core/molecules/LoadingState.tsx"() {
16185
+ "use client";
16186
+ init_cn();
16187
+ init_atoms2();
16188
+ init_Stack();
16189
+ init_Typography();
16190
+ LoadingState = ({
16191
+ title,
16192
+ message,
16193
+ className
16194
+ }) => {
16195
+ const { t } = useTranslate();
16196
+ const displayMessage = message ?? t("common.loading");
16197
+ return /* @__PURE__ */ jsxs(
16198
+ VStack,
16199
+ {
16200
+ align: "center",
16201
+ className: cn(
16202
+ "justify-center py-12",
16203
+ className
16204
+ ),
16205
+ children: [
16206
+ /* @__PURE__ */ jsx(Spinner, { size: "lg" }),
16207
+ title && /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "mt-4 text-lg font-semibold text-foreground", children: title }),
16208
+ /* @__PURE__ */ jsx(
16209
+ Typography,
16210
+ {
16211
+ variant: "small",
16212
+ className: cn(
16213
+ "text-muted-foreground",
16214
+ title ? "mt-2" : "mt-4"
16215
+ ),
16216
+ children: displayMessage
16217
+ }
16218
+ )
16219
+ ]
16220
+ }
16221
+ );
16222
+ };
16223
+ LoadingState.displayName = "LoadingState";
16224
+ }
16225
+ });
16298
16226
  var ICON_NAME_ALIASES, lookStyles3, EmptyState;
16299
16227
  var init_EmptyState = __esm({
16300
16228
  "components/core/molecules/EmptyState.tsx"() {
@@ -16575,7 +16503,7 @@ var init_CodeBlock = __esm({
16575
16503
  };
16576
16504
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
16577
16505
  HIDDEN_LINE_NUMBERS = { display: "none" };
16578
- CodeBlock = React98__default.memo(
16506
+ CodeBlock = React96__default.memo(
16579
16507
  ({
16580
16508
  code: rawCode,
16581
16509
  language = "text",
@@ -17162,7 +17090,7 @@ var init_MarkdownContent = __esm({
17162
17090
  init_Box();
17163
17091
  init_CodeBlock();
17164
17092
  init_cn();
17165
- MarkdownContent = React98__default.memo(
17093
+ MarkdownContent = React96__default.memo(
17166
17094
  ({ content, direction = "ltr", className }) => {
17167
17095
  const { t: _t } = useTranslate();
17168
17096
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -17475,7 +17403,6 @@ function BoardgameBoard({
17475
17403
  units,
17476
17404
  features,
17477
17405
  assetManifest,
17478
- assetBaseUrl,
17479
17406
  scale,
17480
17407
  showMinimap,
17481
17408
  enableCamera,
@@ -18531,7 +18458,7 @@ var init_StateMachineView = __esm({
18531
18458
  style: { top: title ? 30 : 0 },
18532
18459
  children: [
18533
18460
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
18534
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React98__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18461
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React96__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18535
18462
  StateNode,
18536
18463
  {
18537
18464
  state,
@@ -22500,7 +22427,7 @@ function CardHand({
22500
22427
  className
22501
22428
  }) {
22502
22429
  const eventBus = useEventBus();
22503
- const handleClick = React98.useCallback(
22430
+ const handleClick = React96.useCallback(
22504
22431
  (card) => {
22505
22432
  if (card.disabled) return;
22506
22433
  onCardClick?.(card.id);
@@ -22545,7 +22472,7 @@ function CardHand({
22545
22472
  /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
22546
22473
  "img",
22547
22474
  {
22548
- src: card.iconUrl,
22475
+ src: card.iconUrl.url,
22549
22476
  alt: card.title ?? card.id,
22550
22477
  width: art,
22551
22478
  height: art,
@@ -22603,15 +22530,6 @@ var init_CardHand = __esm({
22603
22530
  CardHand.displayName = "CardHand";
22604
22531
  }
22605
22532
  });
22606
- function resolveManifestUrl(manifest, relative) {
22607
- if (relative == null) return void 0;
22608
- if (/^https?:\/\//.test(relative)) return relative;
22609
- const base = manifest?.baseUrl;
22610
- if (base == null) return relative;
22611
- const cleanBase = base.replace(/\/$/, "");
22612
- const cleanRel = relative.replace(/^\//, "");
22613
- return `${cleanBase}/${cleanRel}`;
22614
- }
22615
22533
  function rowToCard(r2) {
22616
22534
  return {
22617
22535
  id: str(r2.id),
@@ -22625,7 +22543,7 @@ function rowToCard(r2) {
22625
22543
  function toHandCards(cards, manifest, mana) {
22626
22544
  return cards.map((c) => {
22627
22545
  const key = c.iconKey ?? c.id;
22628
- const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
22546
+ const iconUrl = manifest?.cards?.[key];
22629
22547
  return {
22630
22548
  id: c.id,
22631
22549
  iconUrl,
@@ -23739,7 +23657,6 @@ function CastleBoard({
23739
23657
  onTileHover: (x, y) => setHoveredTile({ x, y }),
23740
23658
  onTileLeave: () => setHoveredTile(null),
23741
23659
  scale,
23742
- assetBaseUrl: assetManifest?.baseUrl,
23743
23660
  assetManifest,
23744
23661
  backgroundImage
23745
23662
  }
@@ -23815,60 +23732,63 @@ function CastleTemplate({
23815
23732
  }
23816
23733
  );
23817
23734
  }
23818
- var CDN2, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
23735
+ var CDN2, WALL, FLOOR, FLOOR_CENTER, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
23819
23736
  var init_CastleTemplate = __esm({
23820
23737
  "components/game/templates/CastleTemplate.tsx"() {
23821
23738
  init_CastleBoard();
23739
+ init_makeAsset();
23822
23740
  CDN2 = "https://almadar-kflow-assets.web.app/shared";
23741
+ WALL = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`, "tile");
23742
+ FLOOR = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
23743
+ FLOOR_CENTER = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`, "tile");
23823
23744
  DEFAULT_CASTLE_TILES = [
23824
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23825
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23826
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23827
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23828
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23829
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23830
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23831
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23832
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23833
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23834
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23835
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23836
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png` },
23837
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23838
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23839
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23840
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23841
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23842
- { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23843
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23844
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23845
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23846
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23847
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23848
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` }
23745
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23746
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23747
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23748
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23749
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23750
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
23751
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23752
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23753
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23754
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
23755
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
23756
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
23757
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR_CENTER },
23758
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
23759
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
23760
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
23761
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23762
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23763
+ { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23764
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
23765
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23766
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23767
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23768
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23769
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: WALL }
23849
23770
  ];
23850
23771
  DEFAULT_CASTLE_UNITS = [
23851
- { 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` },
23852
- { 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` }
23772
+ { 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") },
23773
+ { 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") }
23853
23774
  ];
23854
23775
  DEFAULT_CASTLE_FEATURES = [
23855
- { id: "f1", x: 2, y: 2, type: "chest", sprite: `${CDN2}/world-map/treasure_chest_closed.png` },
23856
- { id: "f2", x: 3, y: 1, type: "crystal", sprite: `${CDN2}/world-map/resonance_crystal.png` }
23776
+ { id: "f1", x: 2, y: 2, type: "chest", sprite: makeAsset(`${CDN2}/world-map/treasure_chest_closed.png`, "decoration") },
23777
+ { id: "f2", x: 3, y: 1, type: "crystal", sprite: makeAsset(`${CDN2}/world-map/resonance_crystal.png`, "decoration") }
23857
23778
  ];
23858
23779
  DEFAULT_CASTLE_MANIFEST = {
23859
- baseUrl: CDN2,
23860
- terrains: {
23861
- wall: "/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png",
23862
- floor: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png"
23863
- },
23864
- units: {
23865
- worker: "/sprite-sheets/coordinator-sprite-sheet-se.png",
23866
- guardian: "/sprite-sheets/forger-sprite-sheet-se.png"
23867
- },
23868
- features: {
23869
- chest: "/world-map/treasure_chest_closed.png",
23870
- crystal: "/world-map/resonance_crystal.png"
23871
- }
23780
+ terrains: makeAssetMap({
23781
+ wall: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
23782
+ floor: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`
23783
+ }, "tile"),
23784
+ units: makeAssetMap({
23785
+ worker: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`,
23786
+ guardian: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`
23787
+ }, "player"),
23788
+ features: makeAssetMap({
23789
+ chest: `${CDN2}/world-map/treasure_chest_closed.png`,
23790
+ crystal: `${CDN2}/world-map/resonance_crystal.png`
23791
+ }, "decoration")
23872
23792
  };
23873
23793
  CastleTemplate.displayName = "CastleTemplate";
23874
23794
  }
@@ -24856,15 +24776,6 @@ var init_ChatBar = __esm({
24856
24776
  ChatBar.displayName = "ChatBar";
24857
24777
  }
24858
24778
  });
24859
- function resolveManifestUrl2(manifest, relative) {
24860
- if (relative == null) return void 0;
24861
- if (/^https?:\/\//.test(relative)) return relative;
24862
- const base = manifest?.baseUrl;
24863
- if (base == null) return relative;
24864
- const cleanBase = base.replace(/\/$/, "");
24865
- const cleanRel = relative.replace(/^\//, "");
24866
- return `${cleanBase}/${cleanRel}`;
24867
- }
24868
24779
  function buildDefaultCBTiles() {
24869
24780
  const tiles = [];
24870
24781
  for (let y = 0; y < CB_GRID_H; y++) {
@@ -24879,12 +24790,12 @@ function buildDefaultCBTiles() {
24879
24790
  function tilesToIso(tiles, manifest) {
24880
24791
  return tiles.map((t) => {
24881
24792
  const key = t.terrain ?? "grass";
24882
- const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
24793
+ const terrainSprite = t.terrainSprite ?? manifest?.terrains?.[key] ?? manifest?.terrains?.grass;
24883
24794
  return {
24884
24795
  x: t.x,
24885
24796
  y: t.y,
24886
24797
  terrain: t.terrain,
24887
- terrainSprite: sprite,
24798
+ terrainSprite,
24888
24799
  passable: t.passable
24889
24800
  };
24890
24801
  });
@@ -24895,7 +24806,7 @@ function buildingsToFeatures(buildings, manifest) {
24895
24806
  x: b.x,
24896
24807
  y: b.y,
24897
24808
  type: b.type,
24898
- sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
24809
+ sprite: manifest?.features?.[b.type]
24899
24810
  }));
24900
24811
  }
24901
24812
  function CityBuilderBoard({
@@ -24927,7 +24838,7 @@ function CityBuilderBoard({
24927
24838
  x: num(r2.x),
24928
24839
  y: num(r2.y),
24929
24840
  terrain: r2.terrain == null ? void 0 : str(r2.terrain),
24930
- terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
24841
+ terrainSprite: r2.terrainSprite == null ? void 0 : makeAsset(str(r2.terrainSprite), "tile"),
24931
24842
  passable: r2.passable !== false
24932
24843
  })),
24933
24844
  [board.tiles]
@@ -25036,7 +24947,6 @@ function CityBuilderBoard({
25036
24947
  {
25037
24948
  tiles: isoTiles,
25038
24949
  features: buildingFeatures,
25039
- assetBaseUrl: assetManifest?.baseUrl,
25040
24950
  assetManifest,
25041
24951
  validMoves,
25042
24952
  hoveredTile,
@@ -25071,6 +24981,7 @@ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
25071
24981
  var init_CityBuilderBoard = __esm({
25072
24982
  "components/game/organisms/CityBuilderBoard.tsx"() {
25073
24983
  "use client";
24984
+ init_makeAsset();
25074
24985
  init_cn();
25075
24986
  init_useEventBus();
25076
24987
  init_Box();
@@ -25489,10 +25400,10 @@ function CombatLog({
25489
25400
  }, [events2, autoScroll]);
25490
25401
  const safeEvents = events2 ?? [];
25491
25402
  const visibleEvents = safeEvents.slice(-maxVisible);
25492
- return /* @__PURE__ */ jsxs(Card, { variant: "default", className: cn("flex flex-col", className), children: [
25403
+ return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col rounded-container border border-border bg-card shadow-elevation-card", className), children: [
25493
25404
  /* @__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: [
25494
25405
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "font-bold", children: title }),
25495
- /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
25406
+ /* @__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: [
25496
25407
  safeEvents.length,
25497
25408
  " events"
25498
25409
  ] })
@@ -25512,7 +25423,7 @@ function CombatLog({
25512
25423
  /* @__PURE__ */ jsx(Box, { className: cn("flex-shrink-0 mt-0.5", colorClass), children: /* @__PURE__ */ jsx(EventIcon, { className: "h-4 w-4" }) }),
25513
25424
  /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
25514
25425
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "block", children: event.message }),
25515
- event.value !== void 0 && /* @__PURE__ */ jsxs(Badge, { variant: eventBadgeVariants[eventType], size: "sm", className: "mt-1", children: [
25426
+ 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: [
25516
25427
  eventType === "heal" ? "+" : eventType === "attack" ? "-" : "",
25517
25428
  event.value
25518
25429
  ] })
@@ -25525,7 +25436,7 @@ function CombatLog({
25525
25436
  }) }) })
25526
25437
  ] });
25527
25438
  }
25528
- var eventIcons, eventColors, eventBadgeVariants, DEFAULT_COMBAT_EVENTS;
25439
+ var eventIcons, eventColors, eventValueColors, DEFAULT_COMBAT_EVENTS;
25529
25440
  var init_CombatLog = __esm({
25530
25441
  "components/game/molecules/CombatLog.tsx"() {
25531
25442
  init_atoms2();
@@ -25548,14 +25459,14 @@ var init_CombatLog = __esm({
25548
25459
  death: "text-muted-foreground",
25549
25460
  spawn: "text-accent"
25550
25461
  };
25551
- eventBadgeVariants = {
25552
- attack: "danger",
25553
- defend: "primary",
25554
- heal: "success",
25555
- move: "warning",
25556
- special: "secondary",
25557
- death: "secondary",
25558
- spawn: "secondary"
25462
+ eventValueColors = {
25463
+ attack: "text-error bg-error/10 border-error/30",
25464
+ defend: "text-info bg-info/10 border-info/30",
25465
+ heal: "text-success bg-success/10 border-success/30",
25466
+ move: "text-warning bg-warning/10 border-warning/30",
25467
+ special: "text-accent bg-accent/10 border-accent/30",
25468
+ death: "text-muted-foreground bg-muted/30 border-border",
25469
+ spawn: "text-accent bg-accent/10 border-accent/30"
25559
25470
  };
25560
25471
  DEFAULT_COMBAT_EVENTS = [
25561
25472
  { id: "e1", type: "spawn", message: "Shadow Guard entered the field.", timestamp: 0, turn: 1 },
@@ -25979,7 +25890,7 @@ function CraftingRecipe({
25979
25890
  className
25980
25891
  }) {
25981
25892
  const eventBus = useEventBus();
25982
- const handleCraft = React98.useCallback(() => {
25893
+ const handleCraft = React96.useCallback(() => {
25983
25894
  onCraft?.();
25984
25895
  if (craftEvent) {
25985
25896
  eventBus.emit(craftEvent, { output: output.label });
@@ -25996,7 +25907,7 @@ function CraftingRecipe({
25996
25907
  children: [
25997
25908
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
25998
25909
  const hasSufficient = ingredient.available >= ingredient.required;
25999
- return /* @__PURE__ */ jsxs(React98.Fragment, { children: [
25910
+ return /* @__PURE__ */ jsxs(React96.Fragment, { children: [
26000
25911
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
26001
25912
  ItemSlot,
26002
25913
  {
@@ -26021,13 +25932,13 @@ function CraftingRecipe({
26021
25932
  }
26022
25933
  ),
26023
25934
  /* @__PURE__ */ jsx(
26024
- Button,
25935
+ ActionButton,
26025
25936
  {
25937
+ label: "Craft",
26026
25938
  onClick: handleCraft,
26027
25939
  disabled: !canCraft,
26028
25940
  variant: canCraft ? "primary" : "secondary",
26029
- size: "sm",
26030
- children: "Craft"
25941
+ size: "sm"
26031
25942
  }
26032
25943
  )
26033
25944
  ]
@@ -26041,7 +25952,7 @@ var init_CraftingRecipe = __esm({
26041
25952
  init_cn();
26042
25953
  init_useEventBus();
26043
25954
  init_ItemSlot();
26044
- init_Button();
25955
+ init_ActionButton();
26045
25956
  init_Box();
26046
25957
  init_Stack();
26047
25958
  init_Icon();
@@ -26068,8 +25979,8 @@ function DPad({
26068
25979
  }) {
26069
25980
  const eventBus = useEventBus();
26070
25981
  const sizes = sizeMap15[size];
26071
- const [activeDirections, setActiveDirections] = React98.useState(/* @__PURE__ */ new Set());
26072
- const handlePress = React98.useCallback(
25982
+ const [activeDirections, setActiveDirections] = React96.useState(/* @__PURE__ */ new Set());
25983
+ const handlePress = React96.useCallback(
26073
25984
  (direction) => {
26074
25985
  setActiveDirections((prev) => new Set(prev).add(direction));
26075
25986
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -26077,7 +25988,7 @@ function DPad({
26077
25988
  },
26078
25989
  [directionEvent, eventBus, onDirection]
26079
25990
  );
26080
- const handleRelease = React98.useCallback(
25991
+ const handleRelease = React96.useCallback(
26081
25992
  (direction) => {
26082
25993
  setActiveDirections((prev) => {
26083
25994
  const next = new Set(prev);
@@ -26962,8 +26873,8 @@ var init_Menu = __esm({
26962
26873
  "bottom-end": "bottom-start"
26963
26874
  };
26964
26875
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
26965
- const triggerChild = React98__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
26966
- const triggerElement = React98__default.cloneElement(
26876
+ const triggerChild = React96__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
26877
+ const triggerElement = React96__default.cloneElement(
26967
26878
  triggerChild,
26968
26879
  {
26969
26880
  ref: triggerRef,
@@ -27058,14 +26969,14 @@ function useDataDnd(args) {
27058
26969
  const isZone = Boolean(dragGroup || accepts || sortable);
27059
26970
  const enabled = isZone || Boolean(dndRoot);
27060
26971
  const eventBus = useEventBus();
27061
- const parentRoot = React98__default.useContext(RootCtx);
26972
+ const parentRoot = React96__default.useContext(RootCtx);
27062
26973
  const isRoot = enabled && parentRoot === null;
27063
- const zoneId = React98__default.useId();
26974
+ const zoneId = React96__default.useId();
27064
26975
  const ownGroup = dragGroup ?? accepts ?? zoneId;
27065
- const [optimisticOrders, setOptimisticOrders] = React98__default.useState(() => /* @__PURE__ */ new Map());
27066
- const optimisticOrdersRef = React98__default.useRef(optimisticOrders);
26976
+ const [optimisticOrders, setOptimisticOrders] = React96__default.useState(() => /* @__PURE__ */ new Map());
26977
+ const optimisticOrdersRef = React96__default.useRef(optimisticOrders);
27067
26978
  optimisticOrdersRef.current = optimisticOrders;
27068
- const clearOptimisticOrder = React98__default.useCallback((group) => {
26979
+ const clearOptimisticOrder = React96__default.useCallback((group) => {
27069
26980
  setOptimisticOrders((prev) => {
27070
26981
  if (!prev.has(group)) return prev;
27071
26982
  const next = new Map(prev);
@@ -27090,7 +27001,7 @@ function useDataDnd(args) {
27090
27001
  const raw = it[dndItemIdField];
27091
27002
  return raw != null ? String(raw) : `__idx_${idx}`;
27092
27003
  }).join("|");
27093
- const itemIds = React98__default.useMemo(
27004
+ const itemIds = React96__default.useMemo(
27094
27005
  () => orderedItems.map((it, idx) => {
27095
27006
  const raw = it[dndItemIdField];
27096
27007
  return raw != null ? String(raw) : `__idx_${idx}`;
@@ -27101,7 +27012,7 @@ function useDataDnd(args) {
27101
27012
  const raw = it[dndItemIdField];
27102
27013
  return raw != null ? String(raw) : `__${idx}`;
27103
27014
  }).join("|");
27104
- React98__default.useEffect(() => {
27015
+ React96__default.useEffect(() => {
27105
27016
  const root = isRoot ? null : parentRoot;
27106
27017
  if (root) {
27107
27018
  root.clearOptimisticOrder(ownGroup);
@@ -27109,20 +27020,20 @@ function useDataDnd(args) {
27109
27020
  clearOptimisticOrder(ownGroup);
27110
27021
  }
27111
27022
  }, [itemsContentSig, ownGroup]);
27112
- const zonesRef = React98__default.useRef(/* @__PURE__ */ new Map());
27113
- const registerZone = React98__default.useCallback((zoneId2, meta2) => {
27023
+ const zonesRef = React96__default.useRef(/* @__PURE__ */ new Map());
27024
+ const registerZone = React96__default.useCallback((zoneId2, meta2) => {
27114
27025
  zonesRef.current.set(zoneId2, meta2);
27115
27026
  }, []);
27116
- const unregisterZone = React98__default.useCallback((zoneId2) => {
27027
+ const unregisterZone = React96__default.useCallback((zoneId2) => {
27117
27028
  zonesRef.current.delete(zoneId2);
27118
27029
  }, []);
27119
- const [activeDrag, setActiveDrag] = React98__default.useState(null);
27120
- const [overZoneGroup, setOverZoneGroup] = React98__default.useState(null);
27121
- const meta = React98__default.useMemo(
27030
+ const [activeDrag, setActiveDrag] = React96__default.useState(null);
27031
+ const [overZoneGroup, setOverZoneGroup] = React96__default.useState(null);
27032
+ const meta = React96__default.useMemo(
27122
27033
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
27123
27034
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
27124
27035
  );
27125
- React98__default.useEffect(() => {
27036
+ React96__default.useEffect(() => {
27126
27037
  const target = isRoot ? null : parentRoot;
27127
27038
  if (!target) {
27128
27039
  zonesRef.current.set(zoneId, meta);
@@ -27141,7 +27052,7 @@ function useDataDnd(args) {
27141
27052
  }, [parentRoot, isRoot, zoneId, meta]);
27142
27053
  const sensors = useAlmadarDndSensors(true);
27143
27054
  const collisionDetection = almadarDndCollisionDetection;
27144
- const findZoneByItem = React98__default.useCallback(
27055
+ const findZoneByItem = React96__default.useCallback(
27145
27056
  (id) => {
27146
27057
  for (const z of zonesRef.current.values()) {
27147
27058
  if (z.itemIds.includes(id)) return z;
@@ -27150,7 +27061,7 @@ function useDataDnd(args) {
27150
27061
  },
27151
27062
  []
27152
27063
  );
27153
- React98__default.useCallback(
27064
+ React96__default.useCallback(
27154
27065
  (group) => {
27155
27066
  for (const z of zonesRef.current.values()) {
27156
27067
  if (z.group === group) return z;
@@ -27159,7 +27070,7 @@ function useDataDnd(args) {
27159
27070
  },
27160
27071
  []
27161
27072
  );
27162
- const handleDragEnd = React98__default.useCallback(
27073
+ const handleDragEnd = React96__default.useCallback(
27163
27074
  (event) => {
27164
27075
  const { active, over } = event;
27165
27076
  const activeIdStr = String(active.id);
@@ -27250,8 +27161,8 @@ function useDataDnd(args) {
27250
27161
  },
27251
27162
  [eventBus]
27252
27163
  );
27253
- const sortableData = React98__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
27254
- const SortableItem = React98__default.useCallback(
27164
+ const sortableData = React96__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
27165
+ const SortableItem = React96__default.useCallback(
27255
27166
  ({ id, children }) => {
27256
27167
  const {
27257
27168
  attributes,
@@ -27291,7 +27202,7 @@ function useDataDnd(args) {
27291
27202
  id: droppableId,
27292
27203
  data: sortableData
27293
27204
  });
27294
- const ctx = React98__default.useContext(RootCtx);
27205
+ const ctx = React96__default.useContext(RootCtx);
27295
27206
  const activeDrag2 = ctx?.activeDrag ?? null;
27296
27207
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
27297
27208
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -27306,7 +27217,7 @@ function useDataDnd(args) {
27306
27217
  showForeignPlaceholder,
27307
27218
  ctxAvailable: ctx != null
27308
27219
  });
27309
- React98__default.useEffect(() => {
27220
+ React96__default.useEffect(() => {
27310
27221
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
27311
27222
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
27312
27223
  return /* @__PURE__ */ jsx(
@@ -27320,11 +27231,11 @@ function useDataDnd(args) {
27320
27231
  }
27321
27232
  );
27322
27233
  };
27323
- const rootContextValue = React98__default.useMemo(
27234
+ const rootContextValue = React96__default.useMemo(
27324
27235
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
27325
27236
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
27326
27237
  );
27327
- const handleDragStart = React98__default.useCallback((event) => {
27238
+ const handleDragStart = React96__default.useCallback((event) => {
27328
27239
  const sourceZone = findZoneByItem(event.active.id);
27329
27240
  const rect = event.active.rect.current.initial;
27330
27241
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -27343,7 +27254,7 @@ function useDataDnd(args) {
27343
27254
  isRoot
27344
27255
  });
27345
27256
  }, [findZoneByItem, isRoot, zoneId]);
27346
- const handleDragOver = React98__default.useCallback((event) => {
27257
+ const handleDragOver = React96__default.useCallback((event) => {
27347
27258
  const { active, over } = event;
27348
27259
  const overData = over?.data?.current;
27349
27260
  const overGroup = overData?.dndGroup ?? null;
@@ -27413,7 +27324,7 @@ function useDataDnd(args) {
27413
27324
  return next;
27414
27325
  });
27415
27326
  }, []);
27416
- const handleDragCancel = React98__default.useCallback((event) => {
27327
+ const handleDragCancel = React96__default.useCallback((event) => {
27417
27328
  setActiveDrag(null);
27418
27329
  setOverZoneGroup(null);
27419
27330
  dndLog.warn("dragCancel", {
@@ -27421,12 +27332,12 @@ function useDataDnd(args) {
27421
27332
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
27422
27333
  });
27423
27334
  }, []);
27424
- const handleDragEndWithCleanup = React98__default.useCallback((event) => {
27335
+ const handleDragEndWithCleanup = React96__default.useCallback((event) => {
27425
27336
  handleDragEnd(event);
27426
27337
  setActiveDrag(null);
27427
27338
  setOverZoneGroup(null);
27428
27339
  }, [handleDragEnd]);
27429
- const wrapContainer = React98__default.useCallback(
27340
+ const wrapContainer = React96__default.useCallback(
27430
27341
  (children) => {
27431
27342
  if (!enabled) return children;
27432
27343
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -27480,7 +27391,7 @@ var init_useDataDnd = __esm({
27480
27391
  init_useAlmadarDndCollision();
27481
27392
  init_Box();
27482
27393
  dndLog = createLogger("almadar:ui:dnd");
27483
- RootCtx = React98__default.createContext(null);
27394
+ RootCtx = React96__default.createContext(null);
27484
27395
  }
27485
27396
  });
27486
27397
  function renderIconInput(icon, props) {
@@ -28006,7 +27917,7 @@ function DataList({
28006
27917
  }) {
28007
27918
  const eventBus = useEventBus();
28008
27919
  const { t } = useTranslate();
28009
- const [visibleCount, setVisibleCount] = React98__default.useState(pageSize || Infinity);
27920
+ const [visibleCount, setVisibleCount] = React96__default.useState(pageSize || Infinity);
28010
27921
  const fieldDefs = fields ?? columns ?? [];
28011
27922
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
28012
27923
  const dnd = useDataDnd({
@@ -28025,7 +27936,7 @@ function DataList({
28025
27936
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
28026
27937
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
28027
27938
  const hasRenderProp = typeof children === "function";
28028
- React98__default.useEffect(() => {
27939
+ React96__default.useEffect(() => {
28029
27940
  const renderItemTypeOf = typeof schemaRenderItem;
28030
27941
  const childrenTypeOf = typeof children;
28031
27942
  if (data.length > 0 && !hasRenderProp) {
@@ -28129,7 +28040,7 @@ function DataList({
28129
28040
  const items2 = [...data];
28130
28041
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
28131
28042
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
28132
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
28043
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
28133
28044
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
28134
28045
  group.items.map((itemData, index) => {
28135
28046
  const id = itemData.id || `${gi}-${index}`;
@@ -28270,7 +28181,7 @@ function DataList({
28270
28181
  className
28271
28182
  ),
28272
28183
  children: [
28273
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
28184
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
28274
28185
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
28275
28186
  group.items.map(
28276
28187
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -29063,7 +28974,7 @@ var init_Flex = __esm({
29063
28974
  flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
29064
28975
  }
29065
28976
  }
29066
- return React98__default.createElement(Component2, {
28977
+ return React96__default.createElement(Component2, {
29067
28978
  className: cn(
29068
28979
  inline ? "inline-flex" : "flex",
29069
28980
  directionStyles[direction],
@@ -29182,7 +29093,7 @@ var init_Grid = __esm({
29182
29093
  as: Component2 = "div"
29183
29094
  }) => {
29184
29095
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
29185
- return React98__default.createElement(
29096
+ return React96__default.createElement(
29186
29097
  Component2,
29187
29098
  {
29188
29099
  className: cn(
@@ -29378,9 +29289,9 @@ var init_Popover = __esm({
29378
29289
  onMouseLeave: handleClose,
29379
29290
  onPointerDown: tapTriggerProps.onPointerDown
29380
29291
  };
29381
- const childElement = React98__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29292
+ const childElement = React96__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29382
29293
  const childPointerDown = childElement.props.onPointerDown;
29383
- const triggerElement = React98__default.cloneElement(
29294
+ const triggerElement = React96__default.cloneElement(
29384
29295
  childElement,
29385
29296
  {
29386
29297
  ref: triggerRef,
@@ -29982,9 +29893,9 @@ var init_Tooltip = __esm({
29982
29893
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
29983
29894
  };
29984
29895
  }, []);
29985
- const triggerElement = React98__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29896
+ const triggerElement = React96__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29986
29897
  const childPointerDown = triggerElement.props.onPointerDown;
29987
- const trigger = React98__default.cloneElement(triggerElement, {
29898
+ const trigger = React96__default.cloneElement(triggerElement, {
29988
29899
  ref: triggerRef,
29989
29900
  onMouseEnter: handleMouseEnter,
29990
29901
  onMouseLeave: handleMouseLeave,
@@ -30074,7 +29985,7 @@ var init_WizardProgress = __esm({
30074
29985
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
30075
29986
  const isActive = index === currentStep;
30076
29987
  const isCompleted = index < currentStep;
30077
- return /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
29988
+ return /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
30078
29989
  /* @__PURE__ */ jsx(
30079
29990
  "button",
30080
29991
  {
@@ -31037,6 +30948,7 @@ var init_ProgressDots = __esm({
31037
30948
  });
31038
30949
  function StatBadge({
31039
30950
  assetUrl,
30951
+ iconUrl,
31040
30952
  label,
31041
30953
  value = 0,
31042
30954
  max,
@@ -31050,6 +30962,7 @@ function StatBadge({
31050
30962
  field: _field
31051
30963
  }) {
31052
30964
  const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
30965
+ const resolvedAsset = iconUrl ?? assetUrl;
31053
30966
  return /* @__PURE__ */ jsxs(
31054
30967
  "div",
31055
30968
  {
@@ -31060,10 +30973,10 @@ function StatBadge({
31060
30973
  className
31061
30974
  ),
31062
30975
  children: [
31063
- assetUrl ? /* @__PURE__ */ jsx(
30976
+ resolvedAsset ? /* @__PURE__ */ jsx(
31064
30977
  "img",
31065
30978
  {
31066
- src: assetUrl,
30979
+ src: resolvedAsset.url,
31067
30980
  alt: "",
31068
30981
  width: 16,
31069
30982
  height: 16,
@@ -31094,8 +31007,7 @@ function StatBadge({
31094
31007
  ScoreDisplay,
31095
31008
  {
31096
31009
  value: numValue,
31097
- size: size === "lg" ? "md" : "sm",
31098
- animated: true
31010
+ size: size === "lg" ? "md" : "sm"
31099
31011
  }
31100
31012
  ),
31101
31013
  format === "text" && /* @__PURE__ */ jsx("span", { className: "font-bold text-foreground", children: value })
@@ -31138,7 +31050,7 @@ function InventoryGrid({
31138
31050
  const eventBus = useEventBus();
31139
31051
  const slotCount = totalSlots ?? items.length;
31140
31052
  const emptySlotCount = Math.max(0, slotCount - items.length);
31141
- const handleSelect = React98.useCallback(
31053
+ const handleSelect = React96.useCallback(
31142
31054
  (id) => {
31143
31055
  onSelect?.(id);
31144
31056
  if (selectEvent) {
@@ -31245,12 +31157,14 @@ function QuestTracker({
31245
31157
  }
31246
31158
  ),
31247
31159
  /* @__PURE__ */ jsx(Box, { className: "mt-1.5", children: /* @__PURE__ */ jsx(
31248
- ProgressBar,
31160
+ HealthBar,
31249
31161
  {
31250
- value: quest.progress,
31162
+ current: quest.progress,
31251
31163
  max: quest.maxProgress,
31252
- variant: isCompleted ? "success" : isActive ? "primary" : "default",
31253
- size: "sm"
31164
+ format: "bar",
31165
+ size: "sm",
31166
+ animated: true,
31167
+ className: isCompleted ? "[--health-color:var(--color-success)]" : isActive ? "" : "opacity-60"
31254
31168
  }
31255
31169
  ) }),
31256
31170
  /* @__PURE__ */ jsxs(
@@ -31278,7 +31192,7 @@ var init_QuestTracker = __esm({
31278
31192
  "use client";
31279
31193
  init_cn();
31280
31194
  init_WaypointMarker();
31281
- init_ProgressBar();
31195
+ init_HealthBar();
31282
31196
  init_Typography();
31283
31197
  init_Box();
31284
31198
  init_Stack();
@@ -31369,35 +31283,35 @@ function GameCanvas2D({
31369
31283
  tickEvent,
31370
31284
  drawEvent,
31371
31285
  fps = 60,
31372
- backgroundImage = "",
31286
+ backgroundImage,
31373
31287
  assetBaseUrl,
31374
31288
  className
31375
31289
  }) {
31376
- const canvasRef = React98.useRef(null);
31377
- const rafRef = React98.useRef(0);
31378
- const frameRef = React98.useRef(0);
31379
- const lastTimeRef = React98.useRef(0);
31380
- const imageCache = React98.useRef(/* @__PURE__ */ new Map());
31290
+ const canvasRef = React96.useRef(null);
31291
+ const rafRef = React96.useRef(0);
31292
+ const frameRef = React96.useRef(0);
31293
+ const lastTimeRef = React96.useRef(0);
31294
+ const imageCache = React96.useRef(/* @__PURE__ */ new Map());
31381
31295
  const emit = useEmitEvent();
31382
- const onDrawRef = React98.useRef(onDraw);
31296
+ const onDrawRef = React96.useRef(onDraw);
31383
31297
  onDrawRef.current = onDraw;
31384
- const onTickRef = React98.useRef(onTick);
31298
+ const onTickRef = React96.useRef(onTick);
31385
31299
  onTickRef.current = onTick;
31386
- const tickEventRef = React98.useRef(tickEvent);
31300
+ const tickEventRef = React96.useRef(tickEvent);
31387
31301
  tickEventRef.current = tickEvent;
31388
- const drawEventRef = React98.useRef(drawEvent);
31302
+ const drawEventRef = React96.useRef(drawEvent);
31389
31303
  drawEventRef.current = drawEvent;
31390
- const emitRef = React98.useRef(emit);
31304
+ const emitRef = React96.useRef(emit);
31391
31305
  emitRef.current = emit;
31392
- const assetBaseUrlRef = React98.useRef(assetBaseUrl);
31306
+ const assetBaseUrlRef = React96.useRef(assetBaseUrl);
31393
31307
  assetBaseUrlRef.current = assetBaseUrl;
31394
- const backgroundImageRef = React98.useRef(backgroundImage);
31308
+ const backgroundImageRef = React96.useRef(backgroundImage);
31395
31309
  backgroundImageRef.current = backgroundImage;
31396
- const widthRef = React98.useRef(width);
31310
+ const widthRef = React96.useRef(width);
31397
31311
  widthRef.current = width;
31398
- const heightRef = React98.useRef(height);
31312
+ const heightRef = React96.useRef(height);
31399
31313
  heightRef.current = height;
31400
- const loadImage = React98.useCallback((url) => {
31314
+ const loadImage = React96.useCallback((url) => {
31401
31315
  const base = assetBaseUrlRef.current;
31402
31316
  if (!url.startsWith("http") && !base) return null;
31403
31317
  const fullUrl = url.startsWith("http") ? url : `${base}${url}`;
@@ -31411,7 +31325,7 @@ function GameCanvas2D({
31411
31325
  }
31412
31326
  return null;
31413
31327
  }, []);
31414
- React98.useEffect(() => {
31328
+ React96.useEffect(() => {
31415
31329
  const canvas = canvasRef.current;
31416
31330
  if (!canvas) return;
31417
31331
  const ctx = canvas.getContext("2d");
@@ -31433,7 +31347,7 @@ function GameCanvas2D({
31433
31347
  emitRef.current(tickEventRef.current, { dt, frame });
31434
31348
  }
31435
31349
  if (backgroundImageRef.current) {
31436
- const bgImg = loadImage(backgroundImageRef.current);
31350
+ const bgImg = loadImage(backgroundImageRef.current.url);
31437
31351
  if (bgImg) {
31438
31352
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
31439
31353
  } else {
@@ -31559,26 +31473,14 @@ function HealthPanel({
31559
31473
  )
31560
31474
  }
31561
31475
  ),
31562
- effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxs(
31563
- Badge,
31476
+ effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsx(
31477
+ StatusEffect,
31564
31478
  {
31479
+ assetUrl: effect.assetUrl,
31480
+ icon: effect.icon,
31481
+ label: effect.label,
31565
31482
  variant: effectVariantMap[effect.variant ?? "neutral"],
31566
- size: "sm",
31567
- icon: effect.assetUrl ? void 0 : effect.icon,
31568
- children: [
31569
- effect.assetUrl && /* @__PURE__ */ jsx(
31570
- "img",
31571
- {
31572
- src: effect.assetUrl,
31573
- alt: "",
31574
- width: 12,
31575
- height: 12,
31576
- style: { imageRendering: "pixelated", objectFit: "contain" },
31577
- className: "flex-shrink-0 inline-block"
31578
- }
31579
- ),
31580
- effect.label
31581
- ]
31483
+ size: "sm"
31582
31484
  },
31583
31485
  i
31584
31486
  )) })
@@ -31592,17 +31494,17 @@ var init_HealthPanel = __esm({
31592
31494
  "use client";
31593
31495
  init_cn();
31594
31496
  init_HealthBar();
31497
+ init_StatusEffect();
31595
31498
  init_Box();
31596
31499
  init_Typography();
31597
- init_Badge();
31598
31500
  sizeMap18 = {
31599
31501
  sm: { gap: "gap-1", padding: "px-2 py-1.5", text: "text-xs", barSize: "sm" },
31600
31502
  md: { gap: "gap-1.5", padding: "px-3 py-2", text: "text-sm", barSize: "md" },
31601
31503
  lg: { gap: "gap-2", padding: "px-4 py-3", text: "text-base", barSize: "lg" }
31602
31504
  };
31603
31505
  effectVariantMap = {
31604
- buff: "success",
31605
- debuff: "danger",
31506
+ buff: "buff",
31507
+ debuff: "debuff",
31606
31508
  neutral: "neutral"
31607
31509
  };
31608
31510
  HealthPanel.displayName = "HealthPanel";
@@ -31622,13 +31524,13 @@ function ScoreBoard({
31622
31524
  const multiplier = rawMultiplier ?? 1;
31623
31525
  const level = rawLevel ?? 1;
31624
31526
  return /* @__PURE__ */ jsx(
31625
- Card,
31527
+ Box,
31626
31528
  {
31627
31529
  className: cn(
31628
- "bg-[var(--color-card)]/90 border-border backdrop-blur-sm",
31530
+ "rounded-container border border-border bg-[var(--color-card)]/90 backdrop-blur-sm p-3",
31629
31531
  className
31630
31532
  ),
31631
- children: /* @__PURE__ */ jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-wrap", children: [
31533
+ children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-wrap", children: [
31632
31534
  /* @__PURE__ */ jsx(
31633
31535
  StatBadge,
31634
31536
  {
@@ -31670,7 +31572,7 @@ function ScoreBoard({
31670
31572
  }
31671
31573
  ),
31672
31574
  combo != null && combo > 0 && /* @__PURE__ */ jsx(ComboCounter, { combo, multiplier, size: "sm" })
31673
- ] }) })
31575
+ ] })
31674
31576
  }
31675
31577
  );
31676
31578
  }
@@ -31680,7 +31582,6 @@ var init_ScoreBoard = __esm({
31680
31582
  init_cn();
31681
31583
  init_ComboCounter();
31682
31584
  init_StatBadge();
31683
- init_Card();
31684
31585
  init_Box();
31685
31586
  ScoreBoard.displayName = "ScoreBoard";
31686
31587
  }
@@ -31736,7 +31637,7 @@ function TurnPanel({
31736
31637
  className
31737
31638
  }) {
31738
31639
  const eventBus = useEventBus();
31739
- const handleAction = React98.useCallback(
31640
+ const handleAction = React96.useCallback(
31740
31641
  (event) => {
31741
31642
  if (event) {
31742
31643
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -31761,28 +31662,16 @@ function TurnPanel({
31761
31662
  activeTeam
31762
31663
  }
31763
31664
  ),
31764
- actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsxs(
31765
- Button,
31665
+ actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsx(
31666
+ ActionButton,
31766
31667
  {
31767
- variant: "ghost",
31768
- size: "sm",
31668
+ label: action.label,
31669
+ icon: action.assetUrl ? void 0 : action.icon,
31670
+ assetUrl: action.assetUrl,
31769
31671
  disabled: action.disabled,
31770
- leftIcon: action.assetUrl ? void 0 : action.icon,
31771
- onClick: () => handleAction(action.event),
31772
- children: [
31773
- action.assetUrl && /* @__PURE__ */ jsx(
31774
- "img",
31775
- {
31776
- src: action.assetUrl,
31777
- alt: "",
31778
- width: 14,
31779
- height: 14,
31780
- style: { imageRendering: "pixelated", objectFit: "contain" },
31781
- className: "flex-shrink-0"
31782
- }
31783
- ),
31784
- action.label
31785
- ]
31672
+ variant: "secondary",
31673
+ size: "sm",
31674
+ onClick: () => handleAction(action.event)
31786
31675
  },
31787
31676
  i
31788
31677
  )) })
@@ -31796,7 +31685,7 @@ var init_TurnPanel = __esm({
31796
31685
  "use client";
31797
31686
  init_cn();
31798
31687
  init_TurnIndicator();
31799
- init_Button();
31688
+ init_ActionButton();
31800
31689
  init_Box();
31801
31690
  init_useEventBus();
31802
31691
  DEFAULT_TURN_ACTIONS = [
@@ -31829,7 +31718,7 @@ function EnemyPlate({
31829
31718
  assetUrl && /* @__PURE__ */ jsx(
31830
31719
  "img",
31831
31720
  {
31832
- src: assetUrl,
31721
+ src: assetUrl.url,
31833
31722
  alt: name,
31834
31723
  width: 24,
31835
31724
  height: 24,
@@ -31847,7 +31736,7 @@ function EnemyPlate({
31847
31736
  }
31848
31737
  )
31849
31738
  ] }),
31850
- level != null && /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
31739
+ 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: [
31851
31740
  "Lv.",
31852
31741
  level
31853
31742
  ] })
@@ -31878,12 +31767,12 @@ function EnemyPlate({
31878
31767
  )
31879
31768
  ] }),
31880
31769
  effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsx(
31881
- Badge,
31770
+ StatusEffect,
31882
31771
  {
31883
- variant: effectVariantMap2[effect.variant ?? "neutral"],
31884
- size: "sm",
31885
31772
  icon: effect.icon,
31886
- children: effect.label
31773
+ label: effect.label,
31774
+ variant: effectVariantMap2[effect.variant ?? "neutral"],
31775
+ size: "sm"
31887
31776
  },
31888
31777
  i
31889
31778
  )) })
@@ -31897,12 +31786,12 @@ var init_EnemyPlate = __esm({
31897
31786
  "use client";
31898
31787
  init_cn();
31899
31788
  init_HealthBar();
31789
+ init_StatusEffect();
31900
31790
  init_Box();
31901
31791
  init_Typography();
31902
- init_Badge();
31903
31792
  effectVariantMap2 = {
31904
- buff: "success",
31905
- debuff: "danger",
31793
+ buff: "buff",
31794
+ debuff: "debuff",
31906
31795
  neutral: "neutral"
31907
31796
  };
31908
31797
  DEFAULT_ENEMY_EFFECTS = [
@@ -31917,7 +31806,7 @@ function UnitCommandBar({
31917
31806
  className
31918
31807
  }) {
31919
31808
  const eventBus = useEventBus();
31920
- const handleCommand = React98.useCallback(
31809
+ const handleCommand = React96.useCallback(
31921
31810
  (event) => {
31922
31811
  if (event) {
31923
31812
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -31932,27 +31821,18 @@ function UnitCommandBar({
31932
31821
  "flex items-center gap-1.5 rounded-container bg-[var(--color-card)]/90 border border-border backdrop-blur-sm px-2 py-1.5",
31933
31822
  className
31934
31823
  ),
31935
- children: commands.map((command, i) => /* @__PURE__ */ jsxs(Box, { className: "flex flex-col items-center gap-0.5", children: [
31936
- /* @__PURE__ */ jsx(
31937
- Button,
31938
- {
31939
- variant: "ghost",
31940
- size: "sm",
31941
- disabled: command.disabled,
31942
- leftIcon: command.icon,
31943
- onClick: () => handleCommand(command.event),
31944
- children: command.label
31945
- }
31946
- ),
31947
- command.hotkey && /* @__PURE__ */ jsx(
31948
- Typography,
31949
- {
31950
- variant: "caption",
31951
- className: "text-muted-foreground text-xs font-mono",
31952
- children: command.hotkey
31953
- }
31954
- )
31955
- ] }, i))
31824
+ children: commands.map((command, i) => /* @__PURE__ */ jsx(Box, { className: "flex flex-col items-center gap-0.5", children: /* @__PURE__ */ jsx(
31825
+ ActionButton,
31826
+ {
31827
+ label: command.label,
31828
+ icon: command.icon,
31829
+ disabled: command.disabled,
31830
+ hotkey: command.hotkey,
31831
+ variant: "secondary",
31832
+ size: "sm",
31833
+ onClick: () => handleCommand(command.event)
31834
+ }
31835
+ ) }, i))
31956
31836
  }
31957
31837
  );
31958
31838
  }
@@ -31961,9 +31841,8 @@ var init_UnitCommandBar = __esm({
31961
31841
  "components/game/molecules/UnitCommandBar.tsx"() {
31962
31842
  "use client";
31963
31843
  init_cn();
31964
- init_Button();
31844
+ init_ActionButton();
31965
31845
  init_Box();
31966
- init_Typography();
31967
31846
  init_useEventBus();
31968
31847
  DEFAULT_COMMANDS = [
31969
31848
  { label: "Move", icon: "move", event: "MOVE", hotkey: "M" },
@@ -32181,7 +32060,7 @@ function DialogueBox({
32181
32060
  "div",
32182
32061
  {
32183
32062
  className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
32184
- style: { backgroundImage: `url(${backgroundImage})` },
32063
+ style: { backgroundImage: `url(${backgroundImage?.url})` },
32185
32064
  "aria-hidden": "true"
32186
32065
  }
32187
32066
  ),
@@ -32196,7 +32075,7 @@ function DialogueBox({
32196
32075
  children: /* @__PURE__ */ jsx(
32197
32076
  "img",
32198
32077
  {
32199
- src: portraitUrl,
32078
+ src: portraitUrl?.url,
32200
32079
  alt: dialogue.speaker,
32201
32080
  className: "h-full w-auto object-contain drop-shadow-2xl"
32202
32081
  }
@@ -32468,7 +32347,7 @@ function GameMenu({
32468
32347
  } catch {
32469
32348
  }
32470
32349
  const eventBus = eventBusProp || eventBusFromHook;
32471
- const handleOptionClick = React98.useCallback(
32350
+ const handleOptionClick = React96.useCallback(
32472
32351
  (option) => {
32473
32352
  if (option.event && eventBus) {
32474
32353
  eventBus.emit(`UI:${option.event}`, { option });
@@ -32587,7 +32466,7 @@ function GameOverScreen({
32587
32466
  } catch {
32588
32467
  }
32589
32468
  const eventBus = eventBusProp || eventBusFromHook;
32590
- const handleActionClick = React98.useCallback(
32469
+ const handleActionClick = React96.useCallback(
32591
32470
  (action) => {
32592
32471
  if (action.event && eventBus) {
32593
32472
  eventBus.emit(`UI:${action.event}`, { action });
@@ -32802,6 +32681,7 @@ function PlatformerCanvas({
32802
32681
  rightEvent = "MOVE_RIGHT",
32803
32682
  jumpEvent = "JUMP",
32804
32683
  stopEvent = "STOP",
32684
+ effects = [],
32805
32685
  className
32806
32686
  }) {
32807
32687
  const canvasRef = useRef(null);
@@ -32872,7 +32752,8 @@ function PlatformerCanvas({
32872
32752
  playerSprite,
32873
32753
  tileSprites,
32874
32754
  backgroundImage,
32875
- assetBaseUrl
32755
+ assetBaseUrl,
32756
+ effects
32876
32757
  });
32877
32758
  propsRef.current = {
32878
32759
  platforms,
@@ -32885,7 +32766,8 @@ function PlatformerCanvas({
32885
32766
  playerSprite,
32886
32767
  tileSprites,
32887
32768
  backgroundImage,
32888
- assetBaseUrl
32769
+ assetBaseUrl,
32770
+ effects
32889
32771
  };
32890
32772
  const handleKeyDown = useCallback((e) => {
32891
32773
  if (keysRef.current.has(e.code)) return;
@@ -32952,7 +32834,8 @@ function PlatformerCanvas({
32952
32834
  bgColor: bg,
32953
32835
  playerSprite: pSprite,
32954
32836
  tileSprites: tSprites,
32955
- backgroundImage: bgImg
32837
+ backgroundImage: bgImg,
32838
+ effects: fxList
32956
32839
  } = propsRef.current;
32957
32840
  const auth = playerRef.current;
32958
32841
  const interped = positions.get("player");
@@ -33106,6 +32989,18 @@ function PlatformerCanvas({
33106
32989
  ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
33107
32990
  ctx.fill();
33108
32991
  }
32992
+ for (const fx of fxList) {
32993
+ const fxScreenX = fx.x - camX;
32994
+ const fxScreenY = fx.y - camY;
32995
+ const alpha = Math.min(1, fx.ttl / 4);
32996
+ const prev = ctx.globalAlpha;
32997
+ ctx.globalAlpha = alpha;
32998
+ ctx.fillStyle = "#ffe066";
32999
+ ctx.beginPath();
33000
+ ctx.arc(fxScreenX, fxScreenY, 12, 0, Math.PI * 2);
33001
+ ctx.fill();
33002
+ ctx.globalAlpha = prev;
33003
+ }
33109
33004
  };
33110
33005
  return interp.startLoop(drawFrame);
33111
33006
  }, [interp.startLoop, loadImage]);
@@ -33519,13 +33414,13 @@ var init_MapView = __esm({
33519
33414
  shadowSize: [41, 41]
33520
33415
  });
33521
33416
  L.Marker.prototype.options.icon = defaultIcon;
33522
- const { useEffect: useEffect89, useRef: useRef82, useCallback: useCallback133, useState: useState125 } = React98__default;
33417
+ const { useEffect: useEffect87, useRef: useRef82, useCallback: useCallback133, useState: useState123 } = React96__default;
33523
33418
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
33524
33419
  const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
33525
33420
  function MapUpdater({ centerLat, centerLng, zoom }) {
33526
33421
  const map = useMap();
33527
33422
  const prevRef = useRef82({ centerLat, centerLng, zoom });
33528
- useEffect89(() => {
33423
+ useEffect87(() => {
33529
33424
  const prev = prevRef.current;
33530
33425
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
33531
33426
  map.setView([centerLat, centerLng], zoom);
@@ -33536,7 +33431,7 @@ var init_MapView = __esm({
33536
33431
  }
33537
33432
  function MapClickHandler({ onMapClick }) {
33538
33433
  const map = useMap();
33539
- useEffect89(() => {
33434
+ useEffect87(() => {
33540
33435
  if (!onMapClick) return;
33541
33436
  const handler = (e) => {
33542
33437
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -33564,7 +33459,7 @@ var init_MapView = __esm({
33564
33459
  showAttribution = true
33565
33460
  }) {
33566
33461
  const eventBus = useEventBus4();
33567
- const [clickedPosition, setClickedPosition] = useState125(null);
33462
+ const [clickedPosition, setClickedPosition] = useState123(null);
33568
33463
  const handleMapClick = useCallback133((lat, lng) => {
33569
33464
  if (showClickedPin) {
33570
33465
  setClickedPosition({ lat, lng });
@@ -34434,8 +34329,8 @@ function TableView({
34434
34329
  }) {
34435
34330
  const eventBus = useEventBus();
34436
34331
  const { t } = useTranslate();
34437
- const [visibleCount, setVisibleCount] = React98__default.useState(pageSize > 0 ? pageSize : Infinity);
34438
- const [localSelected, setLocalSelected] = React98__default.useState(/* @__PURE__ */ new Set());
34332
+ const [visibleCount, setVisibleCount] = React96__default.useState(pageSize > 0 ? pageSize : Infinity);
34333
+ const [localSelected, setLocalSelected] = React96__default.useState(/* @__PURE__ */ new Set());
34439
34334
  const colDefs = columns ?? fields ?? [];
34440
34335
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
34441
34336
  const dnd = useDataDnd({
@@ -34630,12 +34525,12 @@ function TableView({
34630
34525
  ]
34631
34526
  }
34632
34527
  );
34633
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React98__default.Fragment, { children: rowInner }, id);
34528
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React96__default.Fragment, { children: rowInner }, id);
34634
34529
  };
34635
34530
  const items = Array.from(data);
34636
34531
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
34637
34532
  let runningIndex = 0;
34638
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
34533
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
34639
34534
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
34640
34535
  group.items.map((row) => renderRow(row, runningIndex++))
34641
34536
  ] }, gi)) });
@@ -35992,7 +35887,7 @@ var init_StepFlow = __esm({
35992
35887
  className
35993
35888
  }) => {
35994
35889
  if (orientation === "vertical") {
35995
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React98__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
35890
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React96__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
35996
35891
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
35997
35892
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
35998
35893
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -36003,7 +35898,7 @@ var init_StepFlow = __esm({
36003
35898
  ] })
36004
35899
  ] }) }, index)) });
36005
35900
  }
36006
- 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(React98__default.Fragment, { children: [
35901
+ 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(React96__default.Fragment, { children: [
36007
35902
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
36008
35903
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
36009
35904
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -36988,7 +36883,7 @@ var init_LikertScale = __esm({
36988
36883
  md: "text-base",
36989
36884
  lg: "text-lg"
36990
36885
  };
36991
- LikertScale = React98__default.forwardRef(
36886
+ LikertScale = React96__default.forwardRef(
36992
36887
  ({
36993
36888
  question,
36994
36889
  options = DEFAULT_LIKERT_OPTIONS,
@@ -37000,7 +36895,7 @@ var init_LikertScale = __esm({
37000
36895
  variant = "radios",
37001
36896
  className
37002
36897
  }, ref) => {
37003
- const groupId = React98__default.useId();
36898
+ const groupId = React96__default.useId();
37004
36899
  const eventBus = useEventBus();
37005
36900
  const handleSelect = useCallback(
37006
36901
  (next) => {
@@ -39282,7 +39177,7 @@ var init_DocBreadcrumb = __esm({
39282
39177
  "aria-label": t("aria.breadcrumb"),
39283
39178
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
39284
39179
  const isLast = idx === items.length - 1;
39285
- return /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
39180
+ return /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
39286
39181
  idx > 0 && /* @__PURE__ */ jsx(
39287
39182
  Icon,
39288
39183
  {
@@ -39946,7 +39841,7 @@ var init_PageHeader = __esm({
39946
39841
  info: "bg-info/10 text-info"
39947
39842
  };
39948
39843
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
39949
- 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(React98__default.Fragment, { children: [
39844
+ 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(React96__default.Fragment, { children: [
39950
39845
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
39951
39846
  crumb.href ? /* @__PURE__ */ jsx(
39952
39847
  "a",
@@ -40304,7 +40199,7 @@ var init_Section = __esm({
40304
40199
  as: Component2 = "section"
40305
40200
  }) => {
40306
40201
  const hasHeader = title || description || action;
40307
- return React98__default.createElement(
40202
+ return React96__default.createElement(
40308
40203
  Component2,
40309
40204
  {
40310
40205
  className: cn(
@@ -40672,7 +40567,7 @@ var init_WizardContainer = __esm({
40672
40567
  const isCompleted = index < currentStep;
40673
40568
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
40674
40569
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
40675
- return /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
40570
+ return /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
40676
40571
  /* @__PURE__ */ jsx(
40677
40572
  Button,
40678
40573
  {
@@ -43251,7 +43146,7 @@ var init_DetailPanel = __esm({
43251
43146
  }
43252
43147
  });
43253
43148
  function extractTitle(children) {
43254
- if (!React98__default.isValidElement(children)) return void 0;
43149
+ if (!React96__default.isValidElement(children)) return void 0;
43255
43150
  const props = children.props;
43256
43151
  if (typeof props.title === "string") {
43257
43152
  return props.title;
@@ -43306,7 +43201,7 @@ function LinearView({
43306
43201
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
43307
43202
  const isDone = i < currentIdx;
43308
43203
  const isCurrent = i === currentIdx;
43309
- return /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
43204
+ return /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
43310
43205
  i > 0 && /* @__PURE__ */ jsx(
43311
43206
  Typography,
43312
43207
  {
@@ -44077,7 +43972,6 @@ var init_FeatureGridOrganism = __esm({
44077
43972
  });
44078
43973
  function FishingBoard({
44079
43974
  backgroundImage,
44080
- assetBaseUrl,
44081
43975
  scale = 1,
44082
43976
  showMinimap = false,
44083
43977
  enableCamera = true,
@@ -44095,8 +43989,7 @@ function FishingBoard({
44095
43989
  {
44096
43990
  width,
44097
43991
  height,
44098
- backgroundImage: backgroundImage ?? "",
44099
- assetBaseUrl,
43992
+ backgroundImage,
44100
43993
  fps: 60,
44101
43994
  className: "w-full h-full"
44102
43995
  }
@@ -44292,12 +44185,12 @@ var init_Form = __esm({
44292
44185
  const isSchemaEntity = isOrbitalEntitySchema(entity);
44293
44186
  const resolvedEntity = isSchemaEntity ? entity : void 0;
44294
44187
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
44295
- const normalizedInitialData = React98__default.useMemo(() => {
44188
+ const normalizedInitialData = React96__default.useMemo(() => {
44296
44189
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
44297
44190
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
44298
44191
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
44299
44192
  }, [entity, initialData]);
44300
- const entityDerivedFields = React98__default.useMemo(() => {
44193
+ const entityDerivedFields = React96__default.useMemo(() => {
44301
44194
  if (fields && fields.length > 0) return void 0;
44302
44195
  if (!resolvedEntity) return void 0;
44303
44196
  return resolvedEntity.fields.map(
@@ -44318,16 +44211,16 @@ var init_Form = __esm({
44318
44211
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
44319
44212
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
44320
44213
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
44321
- const [formData, setFormData] = React98__default.useState(
44214
+ const [formData, setFormData] = React96__default.useState(
44322
44215
  normalizedInitialData
44323
44216
  );
44324
- const [collapsedSections, setCollapsedSections] = React98__default.useState(
44217
+ const [collapsedSections, setCollapsedSections] = React96__default.useState(
44325
44218
  /* @__PURE__ */ new Set()
44326
44219
  );
44327
- const [submitError, setSubmitError] = React98__default.useState(null);
44328
- const formRef = React98__default.useRef(null);
44220
+ const [submitError, setSubmitError] = React96__default.useState(null);
44221
+ const formRef = React96__default.useRef(null);
44329
44222
  const formMode = props.mode;
44330
- const mountedRef = React98__default.useRef(false);
44223
+ const mountedRef = React96__default.useRef(false);
44331
44224
  if (!mountedRef.current) {
44332
44225
  mountedRef.current = true;
44333
44226
  debug("forms", "mount", {
@@ -44340,7 +44233,7 @@ var init_Form = __esm({
44340
44233
  });
44341
44234
  }
44342
44235
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
44343
- const evalContext = React98__default.useMemo(
44236
+ const evalContext = React96__default.useMemo(
44344
44237
  () => ({
44345
44238
  formValues: formData,
44346
44239
  globalVariables: externalContext?.globalVariables ?? {},
@@ -44349,7 +44242,7 @@ var init_Form = __esm({
44349
44242
  }),
44350
44243
  [formData, externalContext]
44351
44244
  );
44352
- React98__default.useEffect(() => {
44245
+ React96__default.useEffect(() => {
44353
44246
  debug("forms", "initialData-sync", {
44354
44247
  mode: formMode,
44355
44248
  normalizedInitialData,
@@ -44360,7 +44253,7 @@ var init_Form = __esm({
44360
44253
  setFormData(normalizedInitialData);
44361
44254
  }
44362
44255
  }, [normalizedInitialData]);
44363
- const processCalculations = React98__default.useCallback(
44256
+ const processCalculations = React96__default.useCallback(
44364
44257
  (changedFieldId, newFormData) => {
44365
44258
  if (!hiddenCalculations.length) return;
44366
44259
  const context = {
@@ -44385,7 +44278,7 @@ var init_Form = __esm({
44385
44278
  },
44386
44279
  [hiddenCalculations, externalContext, eventBus]
44387
44280
  );
44388
- const checkViolations = React98__default.useCallback(
44281
+ const checkViolations = React96__default.useCallback(
44389
44282
  (changedFieldId, newFormData) => {
44390
44283
  if (!violationTriggers.length) return;
44391
44284
  const context = {
@@ -44423,7 +44316,7 @@ var init_Form = __esm({
44423
44316
  processCalculations(name, newFormData);
44424
44317
  checkViolations(name, newFormData);
44425
44318
  };
44426
- const isFieldVisible = React98__default.useCallback(
44319
+ const isFieldVisible = React96__default.useCallback(
44427
44320
  (fieldName) => {
44428
44321
  const condition = conditionalFields[fieldName];
44429
44322
  if (!condition) return true;
@@ -44431,7 +44324,7 @@ var init_Form = __esm({
44431
44324
  },
44432
44325
  [conditionalFields, evalContext]
44433
44326
  );
44434
- const isSectionVisible = React98__default.useCallback(
44327
+ const isSectionVisible = React96__default.useCallback(
44435
44328
  (section) => {
44436
44329
  if (!section.condition) return true;
44437
44330
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -44507,7 +44400,7 @@ var init_Form = __esm({
44507
44400
  eventBus.emit(`UI:${onCancel}`);
44508
44401
  }
44509
44402
  };
44510
- const renderField = React98__default.useCallback(
44403
+ const renderField = React96__default.useCallback(
44511
44404
  (field) => {
44512
44405
  const fieldName = field.name || field.field;
44513
44406
  if (!fieldName) return null;
@@ -44528,7 +44421,7 @@ var init_Form = __esm({
44528
44421
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
44529
44422
  );
44530
44423
  const effectiveFields = entityDerivedFields ?? fields;
44531
- const normalizedFields = React98__default.useMemo(() => {
44424
+ const normalizedFields = React96__default.useMemo(() => {
44532
44425
  if (!effectiveFields || effectiveFields.length === 0) return [];
44533
44426
  return effectiveFields.map((field) => {
44534
44427
  if (typeof field === "string") {
@@ -44552,7 +44445,7 @@ var init_Form = __esm({
44552
44445
  return field;
44553
44446
  });
44554
44447
  }, [effectiveFields, resolvedEntity]);
44555
- const schemaFields = React98__default.useMemo(() => {
44448
+ const schemaFields = React96__default.useMemo(() => {
44556
44449
  if (normalizedFields.length === 0) return null;
44557
44450
  if (isDebugEnabled()) {
44558
44451
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -44562,7 +44455,7 @@ var init_Form = __esm({
44562
44455
  }
44563
44456
  return normalizedFields.map(renderField).filter(Boolean);
44564
44457
  }, [normalizedFields, renderField, entityName, conditionalFields]);
44565
- const sectionElements = React98__default.useMemo(() => {
44458
+ const sectionElements = React96__default.useMemo(() => {
44566
44459
  if (!sections || sections.length === 0) return null;
44567
44460
  return sections.map((section) => {
44568
44461
  if (!isSectionVisible(section)) {
@@ -46083,7 +45976,6 @@ var init_GameCanvas3D2 = __esm({
46083
45976
  className,
46084
45977
  isLoading: externalLoading,
46085
45978
  error: externalError,
46086
- entity,
46087
45979
  preloadAssets = [],
46088
45980
  tileClickEvent,
46089
45981
  unitClickEvent,
@@ -46316,7 +46208,7 @@ var init_GameCanvas3D2 = __esm({
46316
46208
  children: /* @__PURE__ */ jsx(
46317
46209
  ModelLoader,
46318
46210
  {
46319
- url: tile.modelUrl,
46211
+ url: tile.modelUrl.url,
46320
46212
  scale: 0.95,
46321
46213
  fallbackGeometry: "box",
46322
46214
  castShadow: true,
@@ -46381,7 +46273,7 @@ var init_GameCanvas3D2 = __esm({
46381
46273
  /* @__PURE__ */ jsx(
46382
46274
  ModelLoader,
46383
46275
  {
46384
- url: unit.modelUrl,
46276
+ url: unit.modelUrl.url,
46385
46277
  scale: modelScale,
46386
46278
  fallbackGeometry: "box",
46387
46279
  castShadow: true
@@ -46441,7 +46333,7 @@ var init_GameCanvas3D2 = __esm({
46441
46333
  return /* @__PURE__ */ jsx(
46442
46334
  ModelLoader,
46443
46335
  {
46444
- url: feature.assetUrl,
46336
+ url: feature.assetUrl.url,
46445
46337
  position,
46446
46338
  scale: 0.5,
46447
46339
  rotation: [0, feature.rotation ?? 0, 0],
@@ -46662,7 +46554,18 @@ function GameBoard3D({
46662
46554
  const row = boardEntity(entity);
46663
46555
  const eventBus = useEventBus();
46664
46556
  const entityUnits = row ? rows(row.units) : [];
46665
- const units = entityUnits;
46557
+ const units = entityUnits.map((r2) => ({
46558
+ id: str(r2.id),
46559
+ x: num(r2.x),
46560
+ y: num(r2.y),
46561
+ z: num(r2.z),
46562
+ faction: str(r2.faction) || "neutral",
46563
+ team: str(r2.team) || str(r2.faction) || "neutral",
46564
+ unitType: r2.unitType == null ? void 0 : str(r2.unitType),
46565
+ name: r2.name == null ? void 0 : str(r2.name),
46566
+ health: r2.health == null ? void 0 : num(r2.health),
46567
+ maxHealth: r2.maxHealth == null ? void 0 : num(r2.maxHealth)
46568
+ }));
46666
46569
  const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
46667
46570
  const phase = row ? str(row.phase) : "observation";
46668
46571
  const result = row ? str(row.result) : "none";
@@ -46819,7 +46722,7 @@ var init_GameBoard3D = __esm({
46819
46722
  }
46820
46723
  });
46821
46724
  function asDescriptor(v) {
46822
- if (Array.isArray(v) || React98__default.isValidElement(v)) return null;
46725
+ if (Array.isArray(v) || React96__default.isValidElement(v)) return null;
46823
46726
  const o = v;
46824
46727
  if (typeof o.type !== "string") return null;
46825
46728
  const props = o.props !== void 0 && typeof o.props === "object" && !Array.isArray(o.props) && o.props !== null ? o.props : void 0;
@@ -46834,10 +46737,10 @@ function getSlotContentRenderer2() {
46834
46737
  }
46835
46738
  function resolveDescriptor(value, idPrefix) {
46836
46739
  if (value === null || value === void 0) return value;
46837
- if (React98__default.isValidElement(value)) return value;
46740
+ if (React96__default.isValidElement(value)) return value;
46838
46741
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
46839
46742
  if (Array.isArray(value)) {
46840
- return value.map((item, i) => /* @__PURE__ */ jsx(React98__default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
46743
+ return value.map((item, i) => /* @__PURE__ */ jsx(React96__default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
46841
46744
  }
46842
46745
  if (typeof value === "object" && value !== null) {
46843
46746
  const desc = asDescriptor(value);
@@ -46937,10 +46840,10 @@ function getSlotContentRenderer3() {
46937
46840
  }
46938
46841
  function resolveDescriptor2(value, idPrefix) {
46939
46842
  if (value === null || value === void 0) return value;
46940
- if (React98__default.isValidElement(value)) return value;
46843
+ if (React96__default.isValidElement(value)) return value;
46941
46844
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
46942
46845
  if (Array.isArray(value)) {
46943
- return value.map((item, i) => /* @__PURE__ */ jsx(React98__default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
46846
+ return value.map((item, i) => /* @__PURE__ */ jsx(React96__default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
46944
46847
  }
46945
46848
  if (typeof value === "object") {
46946
46849
  const rec = value;
@@ -47257,7 +47160,6 @@ function HexStrategyBoard({
47257
47160
  units,
47258
47161
  features,
47259
47162
  assetManifest,
47260
- assetBaseUrl,
47261
47163
  scale,
47262
47164
  showMinimap,
47263
47165
  enableCamera,
@@ -47299,7 +47201,6 @@ function HolidayRunnerBoard({
47299
47201
  units,
47300
47202
  features,
47301
47203
  assetManifest,
47302
- assetBaseUrl,
47303
47204
  scale,
47304
47205
  showMinimap,
47305
47206
  enableCamera,
@@ -47653,7 +47554,7 @@ var init_List = __esm({
47653
47554
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
47654
47555
  return [];
47655
47556
  }, [entity]);
47656
- const getItemActions = React98__default.useCallback(
47557
+ const getItemActions = React96__default.useCallback(
47657
47558
  (item) => {
47658
47559
  if (!itemActions) return [];
47659
47560
  if (typeof itemActions === "function") {
@@ -48094,7 +47995,6 @@ function MatchPuzzleBoard({
48094
47995
  units,
48095
47996
  features,
48096
47997
  assetManifest,
48097
- assetBaseUrl,
48098
47998
  scale,
48099
47999
  showMinimap,
48100
48000
  enableCamera,
@@ -48170,7 +48070,7 @@ var init_MediaGallery = __esm({
48170
48070
  [selectable, selectedItems, selectionEvent, eventBus]
48171
48071
  );
48172
48072
  const entityData = Array.isArray(entity) ? entity : [];
48173
- const items = React98__default.useMemo(() => {
48073
+ const items = React96__default.useMemo(() => {
48174
48074
  if (propItems) return propItems;
48175
48075
  if (entityData.length === 0) return [];
48176
48076
  return entityData.map((record, idx) => {
@@ -48355,7 +48255,6 @@ function MinigolfBoard({
48355
48255
  units,
48356
48256
  features,
48357
48257
  assetManifest,
48358
- assetBaseUrl,
48359
48258
  scale,
48360
48259
  showMinimap,
48361
48260
  enableCamera,
@@ -48375,7 +48274,7 @@ var init_MinigolfBoard = __esm({
48375
48274
  }
48376
48275
  });
48377
48276
  function extractTitle2(children) {
48378
- if (!React98__default.isValidElement(children)) return void 0;
48277
+ if (!React96__default.isValidElement(children)) return void 0;
48379
48278
  const props = children.props;
48380
48279
  if (typeof props.title === "string") {
48381
48280
  return props.title;
@@ -48661,7 +48560,6 @@ function PirateBoard({
48661
48560
  units,
48662
48561
  features,
48663
48562
  assetManifest,
48664
- assetBaseUrl,
48665
48563
  scale,
48666
48564
  showMinimap,
48667
48565
  enableCamera,
@@ -48782,8 +48680,8 @@ function PlatformerBoard({
48782
48680
  canvasHeight,
48783
48681
  followCamera: true,
48784
48682
  bgColor,
48785
- playerSprite,
48786
- tileSprites,
48683
+ playerSprite: playerSprite?.url,
48684
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
48787
48685
  leftEvent,
48788
48686
  rightEvent,
48789
48687
  jumpEvent,
@@ -48848,7 +48746,7 @@ function PlatformerTemplate({
48848
48746
  worldHeight = 400,
48849
48747
  canvasWidth = 800,
48850
48748
  canvasHeight = 400,
48851
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
48749
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
48852
48750
  tileSprites = DEFAULT_TILE_SPRITES,
48853
48751
  bgColor = "#5c94fc",
48854
48752
  gameEndEvent = "GAME_END",
@@ -48901,13 +48799,14 @@ var init_PlatformerTemplate = __esm({
48901
48799
  init_PlatformerBoard();
48902
48800
  init_GameHud();
48903
48801
  init_ScoreBoard();
48802
+ init_makeAsset();
48904
48803
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
48905
- DEFAULT_TILE_SPRITES = {
48804
+ DEFAULT_TILE_SPRITES = makeAssetMap({
48906
48805
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
48907
48806
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
48908
48807
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
48909
48808
  goal: `${CDN3}/tiles/platformPack_tile007.png`
48910
- };
48809
+ }, "tile");
48911
48810
  DEFAULT_PLATFORMS = [
48912
48811
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
48913
48812
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -49063,7 +48962,6 @@ function RacingBoard({
49063
48962
  units,
49064
48963
  features,
49065
48964
  assetManifest,
49066
- assetBaseUrl,
49067
48965
  scale,
49068
48966
  showMinimap,
49069
48967
  enableCamera,
@@ -49082,27 +48980,18 @@ var init_RacingBoard = __esm({
49082
48980
  RacingBoard.displayName = "RacingBoard";
49083
48981
  }
49084
48982
  });
49085
- function resolveManifestUrl3(manifest, relative) {
49086
- if (relative == null) return void 0;
49087
- if (/^https?:\/\//.test(relative)) return relative;
49088
- const base = manifest?.baseUrl;
49089
- if (base == null) return relative;
49090
- const cleanBase = base.replace(/\/$/, "");
49091
- const cleanRel = relative.replace(/^\//, "");
49092
- return `${cleanBase}/${cleanRel}`;
49093
- }
49094
48983
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
49095
48984
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
49096
48985
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
49097
48986
  const isWall = isBorder || isPillar;
49098
48987
  const terrains = manifest?.terrains;
49099
48988
  if (x === stairsX && y === stairsY) {
49100
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
48989
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
49101
48990
  }
49102
48991
  if (isWall) {
49103
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
48992
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
49104
48993
  }
49105
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
48994
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
49106
48995
  }
49107
48996
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
49108
48997
  const tiles = [];
@@ -49146,7 +49035,7 @@ function RoguelikeBoard({
49146
49035
  x: num(r2.x),
49147
49036
  y: num(r2.y),
49148
49037
  terrain: r2.terrain == null ? void 0 : str(r2.terrain),
49149
- terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
49038
+ terrainSprite: r2.terrainSprite == null ? void 0 : makeAsset(str(r2.terrainSprite), "tile"),
49150
49039
  passable: r2.passable !== false
49151
49040
  })),
49152
49041
  [board.tiles]
@@ -49226,7 +49115,7 @@ function RoguelikeBoard({
49226
49115
  health: playerHp,
49227
49116
  maxHealth: playerMaxHp,
49228
49117
  unitType: "player",
49229
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
49118
+ sprite: assetManifest?.units?.player
49230
49119
  },
49231
49120
  ...liveEnemies.map((e) => ({
49232
49121
  id: e.id,
@@ -49236,7 +49125,7 @@ function RoguelikeBoard({
49236
49125
  health: e.hp,
49237
49126
  maxHealth: 6,
49238
49127
  unitType: "enemy",
49239
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
49128
+ sprite: assetManifest?.units?.enemy
49240
49129
  }))
49241
49130
  ];
49242
49131
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -49246,7 +49135,7 @@ function RoguelikeBoard({
49246
49135
  x: it.x,
49247
49136
  y: it.y,
49248
49137
  type: it.kind,
49249
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
49138
+ sprite: assetManifest?.features?.[it.kind]
49250
49139
  })),
49251
49140
  [items, assetManifest]
49252
49141
  );
@@ -49307,7 +49196,6 @@ function RoguelikeBoard({
49307
49196
  onTileHover: (x, y) => setHoveredTile({ x, y }),
49308
49197
  onTileLeave: () => setHoveredTile(null),
49309
49198
  scale,
49310
- assetBaseUrl: assetManifest?.baseUrl,
49311
49199
  assetManifest,
49312
49200
  unitScale,
49313
49201
  spriteHeightRatio,
@@ -49367,6 +49255,7 @@ var init_RoguelikeBoard = __esm({
49367
49255
  init_Stack();
49368
49256
  init_IsometricCanvas();
49369
49257
  init_boardEntity();
49258
+ init_makeAsset();
49370
49259
  DUNGEON_GRID_W = 16;
49371
49260
  DUNGEON_GRID_H = 16;
49372
49261
  DEFAULT_ENEMIES = [
@@ -49417,55 +49306,59 @@ function RoguelikeTemplate({
49417
49306
  }
49418
49307
  );
49419
49308
  }
49420
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49309
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49421
49310
  var init_RoguelikeTemplate = __esm({
49422
49311
  "components/game/templates/RoguelikeTemplate.tsx"() {
49423
49312
  init_RoguelikeBoard();
49313
+ init_makeAsset();
49424
49314
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
49315
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
49316
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
49317
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
49318
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
49425
49319
  DEFAULT_ROGUELIKE_TILES = [
49426
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49427
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49428
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49429
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49430
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49431
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49432
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49433
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49434
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49435
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49436
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49437
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49438
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49439
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49440
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49441
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49442
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49443
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49444
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
49445
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49446
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49447
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49448
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49449
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49450
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
49320
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49321
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49322
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49323
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49324
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49325
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49326
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49327
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49328
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49329
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49330
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49331
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49332
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49333
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
49334
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49335
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49336
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
49337
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
49338
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
49339
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49340
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49341
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49342
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49343
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49344
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
49451
49345
  ];
49452
49346
  DEFAULT_ROGUELIKE_MANIFEST = {
49453
- baseUrl: CDN4,
49454
- terrains: {
49455
- floor: "/isometric-dungeon/Isometric/dirt_E.png",
49456
- wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
49457
- stairs: "/isometric-dungeon/Isometric/stairs_E.png",
49458
- planks: "/isometric-dungeon/Isometric/planks_E.png"
49459
- },
49347
+ terrains: makeAssetMap({
49348
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
49349
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
49350
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
49351
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
49352
+ }, "tile"),
49460
49353
  units: {
49461
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
49462
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
49354
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
49355
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
49463
49356
  },
49464
- features: {
49465
- health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
49466
- sword: "/isometric-dungeon/Isometric/barrel_E.png",
49467
- shield: "/isometric-dungeon/Isometric/barrel_E.png"
49468
- }
49357
+ features: makeAssetMap({
49358
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
49359
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
49360
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
49361
+ }, "item")
49469
49362
  };
49470
49363
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
49471
49364
  }
@@ -49576,7 +49469,7 @@ var init_debugRegistry = __esm({
49576
49469
  }
49577
49470
  });
49578
49471
  function useDebugData() {
49579
- const [data, setData] = React98.useState(() => ({
49472
+ const [data, setData] = React96.useState(() => ({
49580
49473
  traits: [],
49581
49474
  ticks: [],
49582
49475
  guards: [],
@@ -49590,7 +49483,7 @@ function useDebugData() {
49590
49483
  },
49591
49484
  lastUpdate: Date.now()
49592
49485
  }));
49593
- React98.useEffect(() => {
49486
+ React96.useEffect(() => {
49594
49487
  const updateData = () => {
49595
49488
  setData({
49596
49489
  traits: getAllTraits(),
@@ -49699,12 +49592,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
49699
49592
  return positions;
49700
49593
  }
49701
49594
  function WalkMinimap() {
49702
- const [walkStep, setWalkStep] = React98.useState(null);
49703
- const [traits2, setTraits] = React98.useState([]);
49704
- const [coveredEdges, setCoveredEdges] = React98.useState([]);
49705
- const [completedTraits, setCompletedTraits] = React98.useState(/* @__PURE__ */ new Set());
49706
- const prevTraitRef = React98.useRef(null);
49707
- React98.useEffect(() => {
49595
+ const [walkStep, setWalkStep] = React96.useState(null);
49596
+ const [traits2, setTraits] = React96.useState([]);
49597
+ const [coveredEdges, setCoveredEdges] = React96.useState([]);
49598
+ const [completedTraits, setCompletedTraits] = React96.useState(/* @__PURE__ */ new Set());
49599
+ const prevTraitRef = React96.useRef(null);
49600
+ React96.useEffect(() => {
49708
49601
  const interval = setInterval(() => {
49709
49602
  const w = window;
49710
49603
  const step = w.__orbitalWalkStep;
@@ -50140,15 +50033,15 @@ var init_EntitiesTab = __esm({
50140
50033
  });
50141
50034
  function EventFlowTab({ events: events2 }) {
50142
50035
  const { t } = useTranslate();
50143
- const [filter, setFilter] = React98.useState("all");
50144
- const containerRef = React98.useRef(null);
50145
- const [autoScroll, setAutoScroll] = React98.useState(true);
50146
- React98.useEffect(() => {
50036
+ const [filter, setFilter] = React96.useState("all");
50037
+ const containerRef = React96.useRef(null);
50038
+ const [autoScroll, setAutoScroll] = React96.useState(true);
50039
+ React96.useEffect(() => {
50147
50040
  if (autoScroll && containerRef.current) {
50148
50041
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
50149
50042
  }
50150
50043
  }, [events2.length, autoScroll]);
50151
- const filteredEvents = React98.useMemo(() => {
50044
+ const filteredEvents = React96.useMemo(() => {
50152
50045
  if (filter === "all") return events2;
50153
50046
  return events2.filter((e) => e.type === filter);
50154
50047
  }, [events2, filter]);
@@ -50264,7 +50157,7 @@ var init_EventFlowTab = __esm({
50264
50157
  });
50265
50158
  function GuardsPanel({ guards }) {
50266
50159
  const { t } = useTranslate();
50267
- const [filter, setFilter] = React98.useState("all");
50160
+ const [filter, setFilter] = React96.useState("all");
50268
50161
  if (guards.length === 0) {
50269
50162
  return /* @__PURE__ */ jsx(
50270
50163
  EmptyState,
@@ -50277,7 +50170,7 @@ function GuardsPanel({ guards }) {
50277
50170
  }
50278
50171
  const passedCount = guards.filter((g) => g.result).length;
50279
50172
  const failedCount = guards.length - passedCount;
50280
- const filteredGuards = React98.useMemo(() => {
50173
+ const filteredGuards = React96.useMemo(() => {
50281
50174
  if (filter === "all") return guards;
50282
50175
  if (filter === "passed") return guards.filter((g) => g.result);
50283
50176
  return guards.filter((g) => !g.result);
@@ -50440,10 +50333,10 @@ function EffectBadge({ effect }) {
50440
50333
  }
50441
50334
  function TransitionTimeline({ transitions }) {
50442
50335
  const { t } = useTranslate();
50443
- const containerRef = React98.useRef(null);
50444
- const [autoScroll, setAutoScroll] = React98.useState(true);
50445
- const [expandedId, setExpandedId] = React98.useState(null);
50446
- React98.useEffect(() => {
50336
+ const containerRef = React96.useRef(null);
50337
+ const [autoScroll, setAutoScroll] = React96.useState(true);
50338
+ const [expandedId, setExpandedId] = React96.useState(null);
50339
+ React96.useEffect(() => {
50447
50340
  if (autoScroll && containerRef.current) {
50448
50341
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
50449
50342
  }
@@ -50723,9 +50616,9 @@ function getAllEvents(traits2) {
50723
50616
  function EventDispatcherTab({ traits: traits2, schema }) {
50724
50617
  const eventBus = useEventBus();
50725
50618
  const { t } = useTranslate();
50726
- const [log15, setLog] = React98.useState([]);
50727
- const prevStatesRef = React98.useRef(/* @__PURE__ */ new Map());
50728
- React98.useEffect(() => {
50619
+ const [log15, setLog] = React96.useState([]);
50620
+ const prevStatesRef = React96.useRef(/* @__PURE__ */ new Map());
50621
+ React96.useEffect(() => {
50729
50622
  for (const trait of traits2) {
50730
50623
  const prev = prevStatesRef.current.get(trait.id);
50731
50624
  if (prev && prev !== trait.currentState) {
@@ -50894,10 +50787,10 @@ function VerifyModePanel({
50894
50787
  localCount
50895
50788
  }) {
50896
50789
  const { t } = useTranslate();
50897
- const [expanded, setExpanded] = React98.useState(true);
50898
- const scrollRef = React98.useRef(null);
50899
- const prevCountRef = React98.useRef(0);
50900
- React98.useEffect(() => {
50790
+ const [expanded, setExpanded] = React96.useState(true);
50791
+ const scrollRef = React96.useRef(null);
50792
+ const prevCountRef = React96.useRef(0);
50793
+ React96.useEffect(() => {
50901
50794
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
50902
50795
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
50903
50796
  }
@@ -50954,10 +50847,10 @@ function RuntimeDebugger({
50954
50847
  schema
50955
50848
  }) {
50956
50849
  const { t } = useTranslate();
50957
- const [isCollapsed, setIsCollapsed] = React98.useState(mode === "verify" ? true : defaultCollapsed);
50958
- const [isVisible, setIsVisible] = React98.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
50850
+ const [isCollapsed, setIsCollapsed] = React96.useState(mode === "verify" ? true : defaultCollapsed);
50851
+ const [isVisible, setIsVisible] = React96.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
50959
50852
  const debugData = useDebugData();
50960
- React98.useEffect(() => {
50853
+ React96.useEffect(() => {
50961
50854
  if (mode === "inline") return;
50962
50855
  return onDebugToggle((enabled) => {
50963
50856
  setIsVisible(enabled);
@@ -50966,7 +50859,7 @@ function RuntimeDebugger({
50966
50859
  }
50967
50860
  });
50968
50861
  }, [mode]);
50969
- React98.useEffect(() => {
50862
+ React96.useEffect(() => {
50970
50863
  if (mode === "inline") return;
50971
50864
  const handleKeyDown = (e) => {
50972
50865
  if (e.key === "`" && isVisible) {
@@ -51526,7 +51419,7 @@ function SequenceBar({
51526
51419
  onSlotRemove(index);
51527
51420
  }, [onSlotRemove, playing]);
51528
51421
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
51529
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
51422
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
51530
51423
  i > 0 && /* @__PURE__ */ jsx(
51531
51424
  Typography,
51532
51425
  {
@@ -52339,7 +52232,6 @@ function SokobanBoard({
52339
52232
  units,
52340
52233
  features,
52341
52234
  assetManifest,
52342
- assetBaseUrl,
52343
52235
  scale,
52344
52236
  showMinimap,
52345
52237
  enableCamera,
@@ -52381,7 +52273,6 @@ function SpaceShmupBoard({
52381
52273
  units,
52382
52274
  features,
52383
52275
  assetManifest,
52384
- assetBaseUrl,
52385
52276
  scale,
52386
52277
  showMinimap,
52387
52278
  enableCamera,
@@ -52423,7 +52314,6 @@ function SpaceStationBoard({
52423
52314
  units,
52424
52315
  features,
52425
52316
  assetManifest,
52426
- assetBaseUrl,
52427
52317
  scale,
52428
52318
  showMinimap,
52429
52319
  enableCamera,
@@ -52558,7 +52448,6 @@ function SportsBoard({
52558
52448
  units,
52559
52449
  features,
52560
52450
  assetManifest,
52561
- assetBaseUrl,
52562
52451
  scale,
52563
52452
  showMinimap,
52564
52453
  enableCamera,
@@ -52615,7 +52504,7 @@ var init_StatCard = __esm({
52615
52504
  const labelToUse = propLabel ?? propTitle;
52616
52505
  const eventBus = useEventBus();
52617
52506
  const { t } = useTranslate();
52618
- const handleActionClick = React98__default.useCallback(() => {
52507
+ const handleActionClick = React96__default.useCallback(() => {
52619
52508
  if (action?.event) {
52620
52509
  eventBus.emit(`UI:${action.event}`, {});
52621
52510
  }
@@ -52626,7 +52515,7 @@ var init_StatCard = __esm({
52626
52515
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
52627
52516
  const isLoading = externalLoading ?? false;
52628
52517
  const error = externalError;
52629
- const computeMetricValue = React98__default.useCallback(
52518
+ const computeMetricValue = React96__default.useCallback(
52630
52519
  (metric, items) => {
52631
52520
  if (metric.value !== void 0) {
52632
52521
  return metric.value;
@@ -52665,7 +52554,7 @@ var init_StatCard = __esm({
52665
52554
  },
52666
52555
  []
52667
52556
  );
52668
- const schemaStats = React98__default.useMemo(() => {
52557
+ const schemaStats = React96__default.useMemo(() => {
52669
52558
  if (!metrics || metrics.length === 0) return null;
52670
52559
  return metrics.map((metric) => ({
52671
52560
  label: metric.label,
@@ -52673,7 +52562,7 @@ var init_StatCard = __esm({
52673
52562
  format: metric.format
52674
52563
  }));
52675
52564
  }, [metrics, data, computeMetricValue]);
52676
- const calculatedTrend = React98__default.useMemo(() => {
52565
+ const calculatedTrend = React96__default.useMemo(() => {
52677
52566
  if (manualTrend !== void 0) return manualTrend;
52678
52567
  if (previousValue === void 0 || currentValue === void 0)
52679
52568
  return void 0;
@@ -53879,8 +53768,8 @@ var init_SubagentTracePanel = __esm({
53879
53768
  ] });
53880
53769
  };
53881
53770
  InlineActivityStream = ({ activities, autoScroll = true, className }) => {
53882
- const endRef = React98__default.useRef(null);
53883
- React98__default.useEffect(() => {
53771
+ const endRef = React96__default.useRef(null);
53772
+ React96__default.useEffect(() => {
53884
53773
  if (!autoScroll) return;
53885
53774
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
53886
53775
  }, [activities.length, autoScroll]);
@@ -53974,7 +53863,7 @@ var init_SubagentTracePanel = __esm({
53974
53863
  };
53975
53864
  SubagentRichCard = ({ subagent }) => {
53976
53865
  const { t } = useTranslate();
53977
- const activities = React98__default.useMemo(
53866
+ const activities = React96__default.useMemo(
53978
53867
  () => subagentMessagesToActivities(subagent.messages),
53979
53868
  [subagent.messages]
53980
53869
  );
@@ -54051,8 +53940,8 @@ var init_SubagentTracePanel = __esm({
54051
53940
  ] });
54052
53941
  };
54053
53942
  CoordinatorConversation = ({ messages, autoScroll = true, className }) => {
54054
- const endRef = React98__default.useRef(null);
54055
- React98__default.useEffect(() => {
53943
+ const endRef = React96__default.useRef(null);
53944
+ React96__default.useEffect(() => {
54056
53945
  if (!autoScroll) return;
54057
53946
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
54058
53947
  }, [messages.length, autoScroll]);
@@ -54402,7 +54291,6 @@ function TanksBoard({
54402
54291
  units,
54403
54292
  features,
54404
54293
  assetManifest,
54405
- assetBaseUrl,
54406
54294
  scale,
54407
54295
  showMinimap,
54408
54296
  enableCamera,
@@ -54524,7 +54412,7 @@ var init_Timeline = __esm({
54524
54412
  }) => {
54525
54413
  const { t } = useTranslate();
54526
54414
  const entityData = entity ?? [];
54527
- const items = React98__default.useMemo(() => {
54415
+ const items = React96__default.useMemo(() => {
54528
54416
  if (propItems) return propItems;
54529
54417
  if (entityData.length === 0) return [];
54530
54418
  return entityData.map((record, idx) => {
@@ -54626,7 +54514,7 @@ var init_Timeline = __esm({
54626
54514
  }
54627
54515
  });
54628
54516
  function extractToastProps(children) {
54629
- if (!React98__default.isValidElement(children)) {
54517
+ if (!React96__default.isValidElement(children)) {
54630
54518
  if (typeof children === "string") {
54631
54519
  return { message: children };
54632
54520
  }
@@ -54664,7 +54552,7 @@ var init_ToastSlot = __esm({
54664
54552
  eventBus.emit("UI:CLOSE");
54665
54553
  };
54666
54554
  if (!isVisible) return null;
54667
- const isCustomContent = React98__default.isValidElement(children) && !message;
54555
+ const isCustomContent = React96__default.isValidElement(children) && !message;
54668
54556
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
54669
54557
  Toast,
54670
54558
  {
@@ -54680,15 +54568,6 @@ var init_ToastSlot = __esm({
54680
54568
  ToastSlot.displayName = "ToastSlot";
54681
54569
  }
54682
54570
  });
54683
- function resolveManifestUrl4(manifest, relative) {
54684
- if (relative == null || relative === "") return void 0;
54685
- if (/^https?:\/\//.test(relative)) return relative;
54686
- const base = manifest?.baseUrl;
54687
- if (base == null) return relative;
54688
- const cleanBase = base.replace(/\/$/, "");
54689
- const cleanRel = relative.replace(/^\//, "");
54690
- return `${cleanBase}/${cleanRel}`;
54691
- }
54692
54571
  function readPlayer(v) {
54693
54572
  if (v == null || typeof v !== "object") return void 0;
54694
54573
  const o = v;
@@ -54741,10 +54620,10 @@ function TopDownShooterBoard({
54741
54620
  const wave = propWave ?? num(board.wave, 1);
54742
54621
  const lives = propLives ?? num(board.lives, 3);
54743
54622
  const result = propResult ?? (str(board.result) || "none");
54744
- const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
54745
- const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
54746
- const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
54747
- const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
54623
+ const playerSprite = assetManifest?.units?.player?.url;
54624
+ const enemySprite = assetManifest?.units?.enemy?.url;
54625
+ const projectileSprite = assetManifest?.features?.projectile?.url;
54626
+ const backgroundSprite = assetManifest?.background;
54748
54627
  const spriteUrls = useMemo(
54749
54628
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
54750
54629
  [playerSprite, enemySprite, projectileSprite]
@@ -54911,7 +54790,6 @@ function TopDownShooterBoard({
54911
54790
  width,
54912
54791
  height,
54913
54792
  backgroundImage: backgroundSprite,
54914
- assetBaseUrl: assetManifest?.baseUrl,
54915
54793
  onDraw
54916
54794
  }
54917
54795
  ),
@@ -55036,15 +54914,6 @@ var init_TopDownShooterTemplate = __esm({
55036
54914
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
55037
54915
  }
55038
54916
  });
55039
- function resolveManifestUrl5(manifest, relative) {
55040
- if (relative == null) return void 0;
55041
- if (/^https?:\/\//.test(relative)) return relative;
55042
- const base = manifest?.baseUrl;
55043
- if (base == null) return relative;
55044
- const cleanBase = base.replace(/\/$/, "");
55045
- const cleanRel = relative.replace(/^\//, "");
55046
- return `${cleanBase}/${cleanRel}`;
55047
- }
55048
54917
  function buildDefaultTDTiles() {
55049
54918
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
55050
54919
  const tiles = [];
@@ -55064,18 +54933,18 @@ function buildDefaultTDTiles() {
55064
54933
  function tilesToIso2(tiles, manifest) {
55065
54934
  return tiles.map((t) => {
55066
54935
  const key = t.terrain ?? "ground";
55067
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
54936
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
55068
54937
  return {
55069
54938
  x: t.x,
55070
54939
  y: t.y,
55071
54940
  terrain: t.terrain,
55072
- terrainSprite: sprite,
54941
+ terrainSprite,
55073
54942
  passable: t.passable
55074
54943
  };
55075
54944
  });
55076
54945
  }
55077
54946
  function creepsToUnits(creeps, manifest) {
55078
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
54947
+ const sprite = manifest?.units?.creep;
55079
54948
  return creeps.map((c) => ({
55080
54949
  id: c.id,
55081
54950
  position: { x: c.x, y: c.y },
@@ -55093,14 +54962,14 @@ function heroToUnit(hero, manifest) {
55093
54962
  position: { x: hero.x, y: hero.y },
55094
54963
  name: "Hero",
55095
54964
  team: "player",
55096
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
54965
+ sprite: manifest?.units?.hero,
55097
54966
  unitType: "hero",
55098
54967
  health: 1,
55099
54968
  maxHealth: 1
55100
54969
  };
55101
54970
  }
55102
54971
  function towersToFeatures(towers, manifest) {
55103
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
54972
+ const sprite = manifest?.features?.tower;
55104
54973
  return towers.map((t) => ({
55105
54974
  id: t.id,
55106
54975
  x: t.x,
@@ -55298,7 +55167,6 @@ function TowerDefenseBoard({
55298
55167
  tiles: isoTiles,
55299
55168
  units: isoUnits,
55300
55169
  features: towerFeatures,
55301
- assetBaseUrl: assetManifest?.baseUrl,
55302
55170
  assetManifest,
55303
55171
  validMoves,
55304
55172
  hoveredTile,
@@ -55342,6 +55210,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
55342
55210
  var init_TowerDefenseBoard = __esm({
55343
55211
  "components/game/organisms/TowerDefenseBoard.tsx"() {
55344
55212
  "use client";
55213
+ init_makeAsset();
55345
55214
  init_cn();
55346
55215
  init_useEventBus();
55347
55216
  init_Box();
@@ -55671,15 +55540,6 @@ var init_UncontrolledBattleBoard = __esm({
55671
55540
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
55672
55541
  }
55673
55542
  });
55674
- function resolveManifestUrl6(manifest, relative) {
55675
- if (relative == null) return void 0;
55676
- if (/^https?:\/\//.test(relative)) return relative;
55677
- const base = manifest?.baseUrl;
55678
- if (base == null) return relative;
55679
- const cleanBase = base.replace(/\/$/, "");
55680
- const cleanRel = relative.replace(/^\//, "");
55681
- return `${cleanBase}/${cleanRel}`;
55682
- }
55683
55543
  function VisualNovelBoard({
55684
55544
  entity,
55685
55545
  nodes: propNodes,
@@ -55714,11 +55574,11 @@ function VisualNovelBoard({
55714
55574
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
55715
55575
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
55716
55576
  const backgroundImage = useMemo(
55717
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
55577
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
55718
55578
  [assetManifest, currentNode?.backgroundKey]
55719
55579
  );
55720
55580
  const portraitUrl = useMemo(
55721
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
55581
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
55722
55582
  [assetManifest, currentNode?.portraitKey]
55723
55583
  );
55724
55584
  const dialogueChoices = useMemo(
@@ -55892,7 +55752,7 @@ function buildDefaultWorldTiles() {
55892
55752
  for (let x = 0; x < WORLD_GRID_W; x++) {
55893
55753
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
55894
55754
  const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
55895
- tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
55755
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
55896
55756
  }
55897
55757
  }
55898
55758
  return tiles;
@@ -55936,7 +55796,12 @@ function WorldMapBoard({
55936
55796
  const resolved = boardEntity(entity);
55937
55797
  const entityUnits = rows(resolved?.units);
55938
55798
  const entityTiles = rows(resolved?.tiles);
55939
- const features = propFeatures ?? rows(resolved?.features);
55799
+ const features = propFeatures ?? rows(resolved?.features).map((r2) => ({
55800
+ id: r2.id == null ? void 0 : str(r2.id),
55801
+ x: num(r2.x),
55802
+ y: num(r2.y),
55803
+ type: str(r2.type)
55804
+ }));
55940
55805
  const selectedHeroId = resolved?.selectedHeroId ?? null;
55941
55806
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
55942
55807
  const backgroundImage = resolved?.backgroundImage;
@@ -55946,7 +55811,7 @@ function WorldMapBoard({
55946
55811
  x: num(t.x),
55947
55812
  y: num(t.y),
55948
55813
  terrain: str(t.terrain),
55949
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
55814
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
55950
55815
  passable: t.passable !== false
55951
55816
  })),
55952
55817
  [entityTiles]
@@ -55962,7 +55827,7 @@ function WorldMapBoard({
55962
55827
  team: str(u.team) === "enemy" ? "enemy" : "player",
55963
55828
  health: num(u.health) || 100,
55964
55829
  maxHealth: num(u.maxHealth) || 100,
55965
- sprite: u.sprite == null ? void 0 : str(u.sprite)
55830
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
55966
55831
  })),
55967
55832
  [entityUnits, propUnits]
55968
55833
  );
@@ -56144,7 +56009,6 @@ function WorldMapBoard({
56144
56009
  onTileHover: (x, y) => setHoveredTile({ x, y }),
56145
56010
  onTileLeave: () => setHoveredTile(null),
56146
56011
  scale,
56147
- assetBaseUrl: assetManifest?.baseUrl,
56148
56012
  assetManifest,
56149
56013
  backgroundImage,
56150
56014
  effectSpriteUrls,
@@ -56167,6 +56031,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
56167
56031
  var init_WorldMapBoard = __esm({
56168
56032
  "components/game/organisms/WorldMapBoard.tsx"() {
56169
56033
  "use client";
56034
+ init_makeAsset();
56170
56035
  init_cn();
56171
56036
  init_useEventBus();
56172
56037
  init_Stack();
@@ -56220,68 +56085,72 @@ function WorldMapTemplate({
56220
56085
  }
56221
56086
  );
56222
56087
  }
56223
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56088
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56224
56089
  var init_WorldMapTemplate = __esm({
56225
56090
  "components/game/templates/WorldMapTemplate.tsx"() {
56226
56091
  init_WorldMapBoard();
56092
+ init_makeAsset();
56227
56093
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
56094
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
56095
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
56096
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
56097
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
56228
56098
  DEFAULT_WORLDMAP_TILES = [
56229
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56230
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56231
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56232
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56233
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56234
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56235
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56236
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56237
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56238
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56239
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56240
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56241
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
56242
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56243
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56244
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56245
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56246
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56247
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
56248
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56249
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56250
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56251
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56252
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56253
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
56099
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56100
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56101
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
56102
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56103
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56104
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
56105
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56106
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56107
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56108
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
56109
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
56110
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56111
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
56112
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56113
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
56114
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56115
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56116
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56117
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
56118
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56119
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56120
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
56121
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
56122
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56123
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
56254
56124
  ];
56255
56125
  DEFAULT_WORLDMAP_UNITS = [
56256
- { 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` },
56257
- { 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` }
56126
+ { 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") },
56127
+ { 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") }
56258
56128
  ];
56259
56129
  DEFAULT_WORLDMAP_FEATURES = [
56260
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
56261
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
56130
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
56131
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
56262
56132
  ];
56263
56133
  DEFAULT_WORLDMAP_MANIFEST = {
56264
- baseUrl: CDN5,
56265
- terrains: {
56266
- grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
56267
- water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
56268
- mountain: "/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png",
56269
- road: "/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png"
56270
- },
56134
+ terrains: makeAssetMap({
56135
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
56136
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
56137
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
56138
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
56139
+ }, "tile"),
56271
56140
  units: {
56272
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
56273
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
56141
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
56142
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
56274
56143
  },
56275
- features: {
56276
- capital: "/scenes/world/capital.png",
56277
- power_node: "/world-map/power_node.png"
56278
- }
56144
+ features: makeAssetMap({
56145
+ capital: `${CDN5}/scenes/world/capital.png`,
56146
+ power_node: `${CDN5}/world-map/power_node.png`
56147
+ }, "decoration")
56279
56148
  };
56280
56149
  WorldMapTemplate.displayName = "WorldMapTemplate";
56281
56150
  }
56282
56151
  });
56283
56152
  function lazyThree(name, loader) {
56284
- const Lazy = React98__default.lazy(
56153
+ const Lazy = React96__default.lazy(
56285
56154
  () => loader().then((m) => {
56286
56155
  const Resolved = m[name];
56287
56156
  if (!Resolved) {
@@ -56293,13 +56162,13 @@ function lazyThree(name, loader) {
56293
56162
  })
56294
56163
  );
56295
56164
  function ThreeWrapper(props) {
56296
- return React98__default.createElement(
56165
+ return React96__default.createElement(
56297
56166
  ThreeBoundary,
56298
56167
  { name },
56299
- React98__default.createElement(
56300
- React98__default.Suspense,
56168
+ React96__default.createElement(
56169
+ React96__default.Suspense,
56301
56170
  { fallback: null },
56302
- React98__default.createElement(Lazy, props)
56171
+ React96__default.createElement(Lazy, props)
56303
56172
  )
56304
56173
  );
56305
56174
  }
@@ -56622,7 +56491,7 @@ var init_component_registry_generated = __esm({
56622
56491
  init_WorldMapBoard();
56623
56492
  init_WorldMapTemplate();
56624
56493
  init_XPBar();
56625
- ThreeBoundary = class extends React98__default.Component {
56494
+ ThreeBoundary = class extends React96__default.Component {
56626
56495
  constructor() {
56627
56496
  super(...arguments);
56628
56497
  __publicField(this, "state", { failed: false });
@@ -56632,7 +56501,7 @@ var init_component_registry_generated = __esm({
56632
56501
  }
56633
56502
  render() {
56634
56503
  if (this.state.failed) {
56635
- return React98__default.createElement(
56504
+ return React96__default.createElement(
56636
56505
  "div",
56637
56506
  {
56638
56507
  "data-testid": "three-unavailable",
@@ -56998,7 +56867,7 @@ function SuspenseConfigProvider({
56998
56867
  config,
56999
56868
  children
57000
56869
  }) {
57001
- return React98__default.createElement(
56870
+ return React96__default.createElement(
57002
56871
  SuspenseConfigContext.Provider,
57003
56872
  { value: config },
57004
56873
  children
@@ -57040,7 +56909,7 @@ function enrichFormFields(fields, entityDef) {
57040
56909
  }
57041
56910
  return { name: field, label: field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()) };
57042
56911
  }
57043
- if (field && typeof field === "object" && !Array.isArray(field) && !React98__default.isValidElement(field) && !(field instanceof Date)) {
56912
+ if (field && typeof field === "object" && !Array.isArray(field) && !React96__default.isValidElement(field) && !(field instanceof Date)) {
57044
56913
  const obj = field;
57045
56914
  const fieldName = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
57046
56915
  if (!fieldName) return field;
@@ -57486,7 +57355,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
57486
57355
  const key = `${parentId}-${index}-trait:${traitName}`;
57487
57356
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
57488
57357
  }
57489
- return /* @__PURE__ */ jsx(React98__default.Fragment, { children: child }, `${parentId}-${index}`);
57358
+ return /* @__PURE__ */ jsx(React96__default.Fragment, { children: child }, `${parentId}-${index}`);
57490
57359
  }
57491
57360
  if (!child || typeof child !== "object") return null;
57492
57361
  const childId = `${parentId}-${index}`;
@@ -57526,14 +57395,14 @@ function isPatternConfig(value) {
57526
57395
  if (value === null || value === void 0) return false;
57527
57396
  if (typeof value !== "object") return false;
57528
57397
  if (Array.isArray(value)) return false;
57529
- if (React98__default.isValidElement(value)) return false;
57398
+ if (React96__default.isValidElement(value)) return false;
57530
57399
  if (value instanceof Date) return false;
57531
57400
  if (typeof value === "function") return false;
57532
57401
  const record = value;
57533
57402
  return "type" in record && typeof record.type === "string" && getComponentForPattern(record.type) !== null;
57534
57403
  }
57535
57404
  function isPlainConfigObject(value) {
57536
- if (React98__default.isValidElement(value)) return false;
57405
+ if (React96__default.isValidElement(value)) return false;
57537
57406
  if (value instanceof Date) return false;
57538
57407
  const proto = Object.getPrototypeOf(value);
57539
57408
  return proto === Object.prototype || proto === null;
@@ -57659,7 +57528,7 @@ function SlotContentRenderer({
57659
57528
  for (const slotKey of CONTENT_NODE_SLOTS) {
57660
57529
  const slotVal = restProps[slotKey];
57661
57530
  if (slotVal === void 0 || slotVal === null) continue;
57662
- if (React98__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
57531
+ if (React96__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
57663
57532
  if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
57664
57533
  nodeSlotOverrides[slotKey] = renderPatternChildren(
57665
57534
  slotVal,
@@ -57708,7 +57577,7 @@ function SlotContentRenderer({
57708
57577
  const resolvedItems = Array.isArray(entityVal) && entityVal[0] !== "fn" ? entityVal : null;
57709
57578
  if (resolvedItems && resolvedItems.length > 0 && !finalProps.fields && !finalProps.columns) {
57710
57579
  const sample = resolvedItems[0];
57711
- if (sample && typeof sample === "object" && !Array.isArray(sample) && !React98__default.isValidElement(sample) && !(sample instanceof Date)) {
57580
+ if (sample && typeof sample === "object" && !Array.isArray(sample) && !React96__default.isValidElement(sample) && !(sample instanceof Date)) {
57712
57581
  const keys = Object.keys(sample).filter((k) => k !== "id" && k !== "_id");
57713
57582
  finalProps.fields = keys.map((k, i) => ({ name: k, variant: i === 0 ? "h4" : "body" }));
57714
57583
  }
@@ -58071,7 +57940,7 @@ var AvlTransition = ({
58071
57940
  opacity = 1,
58072
57941
  className
58073
57942
  }) => {
58074
- const ids = React98__default.useMemo(() => {
57943
+ const ids = React96__default.useMemo(() => {
58075
57944
  avlTransitionId += 1;
58076
57945
  return { arrow: `avl-tr-${avlTransitionId}-arrow` };
58077
57946
  }, []);
@@ -58632,7 +58501,7 @@ var AvlStateMachine = ({
58632
58501
  color = "var(--color-primary)",
58633
58502
  animated = false
58634
58503
  }) => {
58635
- const ids = React98__default.useMemo(() => {
58504
+ const ids = React96__default.useMemo(() => {
58636
58505
  avlSmId += 1;
58637
58506
  const base = `avl-sm-${avlSmId}`;
58638
58507
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -58831,7 +58700,7 @@ var AvlOrbitalUnit = ({
58831
58700
  color = "var(--color-primary)",
58832
58701
  animated = false
58833
58702
  }) => {
58834
- const ids = React98__default.useMemo(() => {
58703
+ const ids = React96__default.useMemo(() => {
58835
58704
  avlOuId += 1;
58836
58705
  const base = `avl-ou-${avlOuId}`;
58837
58706
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -58927,7 +58796,7 @@ var AvlClosedCircuit = ({
58927
58796
  color = "var(--color-primary)",
58928
58797
  animated = false
58929
58798
  }) => {
58930
- const ids = React98__default.useMemo(() => {
58799
+ const ids = React96__default.useMemo(() => {
58931
58800
  avlCcId += 1;
58932
58801
  const base = `avl-cc-${avlCcId}`;
58933
58802
  return { glow: `${base}-glow`, grad: `${base}-grad`, arrow: `${base}-arrow` };
@@ -59082,7 +58951,7 @@ var AvlEmitListen = ({
59082
58951
  color = "var(--color-primary)",
59083
58952
  animated = false
59084
58953
  }) => {
59085
- const ids = React98__default.useMemo(() => {
58954
+ const ids = React96__default.useMemo(() => {
59086
58955
  avlElId += 1;
59087
58956
  const base = `avl-el-${avlElId}`;
59088
58957
  return { arrow: `${base}-arrow`, grad: `${base}-grad` };
@@ -59356,7 +59225,7 @@ function renderNode(node, color, glowId) {
59356
59225
  const baseR = node.type === "operator" ? 20 : 16;
59357
59226
  const r2 = Math.max(baseR, labelLen * 3.5 + 6);
59358
59227
  const nc = nodeColor(node.type, color);
59359
- return /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
59228
+ return /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
59360
59229
  node.children.map((child, i) => {
59361
59230
  const childR = Math.max(
59362
59231
  child.type === "operator" ? 20 : 16,
@@ -59413,7 +59282,7 @@ var AvlExprTree = ({
59413
59282
  className,
59414
59283
  color = "var(--color-primary)"
59415
59284
  }) => {
59416
- const ids = React98__default.useMemo(() => {
59285
+ const ids = React96__default.useMemo(() => {
59417
59286
  avlEtId += 1;
59418
59287
  return { glow: `avl-et-${avlEtId}-glow` };
59419
59288
  }, []);
@@ -60248,7 +60117,7 @@ var SystemNode = ({ data }) => {
60248
60117
  stateChain.length > 0 && /* @__PURE__ */ jsx("svg", { width: stateChain.length * 14 + 2, height: 10, viewBox: `0 0 ${stateChain.length * 14 + 2} 10`, children: stateChain.map((s, i) => {
60249
60118
  const tc = transitionCounts[s.name] ?? 0;
60250
60119
  const role = getStateRole(s.name, s.isInitial ?? void 0, s.isTerminal ?? void 0, tc, maxTC);
60251
- return /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
60120
+ return /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
60252
60121
  /* @__PURE__ */ jsx(AvlState, { x: i * 14 + 1, y: 1, width: 10, height: 8, name: "", role, isInitial: s.isInitial ?? void 0, isTerminal: s.isTerminal ?? void 0 }),
60253
60122
  i < stateChain.length - 1 && /* @__PURE__ */ jsx("line", { x1: i * 14 + 12, y1: 5, x2: i * 14 + 15, y2: 5, stroke: "var(--color-border)", strokeWidth: 0.5 })
60254
60123
  ] }, s.name);
@@ -61398,7 +61267,7 @@ function resolveLambdaBindings(body, params, item, index) {
61398
61267
  if (Array.isArray(body)) {
61399
61268
  return body.map((b) => recur(b));
61400
61269
  }
61401
- if (body !== null && typeof body === "object" && !React98__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
61270
+ if (body !== null && typeof body === "object" && !React96__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
61402
61271
  const out = {};
61403
61272
  for (const [k, v] of Object.entries(body)) {
61404
61273
  out[k] = recur(v);
@@ -61417,7 +61286,7 @@ function getSlotContentRenderer4() {
61417
61286
  function makeLambdaFn(params, lambdaBody, callerKey) {
61418
61287
  return (item, index) => {
61419
61288
  const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
61420
- if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React98__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
61289
+ if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React96__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
61421
61290
  return null;
61422
61291
  }
61423
61292
  const record = resolvedBody;
@@ -61436,7 +61305,7 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
61436
61305
  props: childProps,
61437
61306
  priority: 0
61438
61307
  };
61439
- return React98__default.createElement(SlotContentRenderer2, { content: childContent });
61308
+ return React96__default.createElement(SlotContentRenderer2, { content: childContent });
61440
61309
  };
61441
61310
  }
61442
61311
  function convertNode(node, callerKey) {
@@ -61455,7 +61324,7 @@ function convertNode(node, callerKey) {
61455
61324
  });
61456
61325
  return anyChanged ? mapped : node;
61457
61326
  }
61458
- if (typeof node === "object" && !React98__default.isValidElement(node) && !(node instanceof Date)) {
61327
+ if (typeof node === "object" && !React96__default.isValidElement(node) && !(node instanceof Date)) {
61459
61328
  return convertObjectProps(node);
61460
61329
  }
61461
61330
  return node;
@@ -63687,8 +63556,8 @@ function CanvasDndProvider({
63687
63556
  }) {
63688
63557
  const eventBus = useEventBus();
63689
63558
  const sensors = useAlmadarDndSensors(false);
63690
- const [activePayload, setActivePayload] = React98__default.useState(null);
63691
- const handleDragStart = React98__default.useCallback((e) => {
63559
+ const [activePayload, setActivePayload] = React96__default.useState(null);
63560
+ const handleDragStart = React96__default.useCallback((e) => {
63692
63561
  const data = e.active.data.current;
63693
63562
  const payload = data?.payload;
63694
63563
  if (payload) {
@@ -63699,7 +63568,7 @@ function CanvasDndProvider({
63699
63568
  log13.warn("dragStart:missing-payload", { id: e.active.id });
63700
63569
  }
63701
63570
  }, [eventBus]);
63702
- const handleDragEnd = React98__default.useCallback((e) => {
63571
+ const handleDragEnd = React96__default.useCallback((e) => {
63703
63572
  setActivePayload(null);
63704
63573
  const activeData = e.active.data.current;
63705
63574
  const payload = activeData?.payload;
@@ -63728,7 +63597,7 @@ function CanvasDndProvider({
63728
63597
  const suppressed = onDrop ? onDrop(drop) === true : false;
63729
63598
  if (!suppressed) defaultEmit(eventBus, drop);
63730
63599
  }, [eventBus, onDrop]);
63731
- const handleDragCancel = React98__default.useCallback(() => {
63600
+ const handleDragCancel = React96__default.useCallback(() => {
63732
63601
  setActivePayload(null);
63733
63602
  log13.info("dragCancel");
63734
63603
  }, []);
@@ -64486,7 +64355,7 @@ var OrbPreviewNodeInner = (props) => {
64486
64355
  }
64487
64356
  );
64488
64357
  };
64489
- var OrbPreviewNode = React98__default.memo(OrbPreviewNodeInner);
64358
+ var OrbPreviewNode = React96__default.memo(OrbPreviewNodeInner);
64490
64359
  OrbPreviewNode.displayName = "OrbPreviewNode";
64491
64360
  orbPreviewLog.debug("export-resolved", () => ({
64492
64361
  type: typeof OrbPreviewNode,
@@ -64591,7 +64460,7 @@ var EventFlowEdgeInner = (props) => {
64591
64460
  ) })
64592
64461
  ] });
64593
64462
  };
64594
- var EventFlowEdge = React98__default.memo(EventFlowEdgeInner);
64463
+ var EventFlowEdge = React96__default.memo(EventFlowEdgeInner);
64595
64464
  EventFlowEdge.displayName = "EventFlowEdge";
64596
64465
 
64597
64466
  // components/avl/molecules/BehaviorComposeNode.tsx
@@ -64738,7 +64607,7 @@ var BehaviorComposeNodeInner = (props) => {
64738
64607
  }
64739
64608
  );
64740
64609
  };
64741
- var BehaviorComposeNode = React98__default.memo(BehaviorComposeNodeInner);
64610
+ var BehaviorComposeNode = React96__default.memo(BehaviorComposeNodeInner);
64742
64611
  BehaviorComposeNode.displayName = "BehaviorComposeNode";
64743
64612
 
64744
64613
  // components/avl/molecules/avl-behavior-compose-converter.ts
@@ -65764,7 +65633,7 @@ var TraitCardNodeInner = (props) => {
65764
65633
  }
65765
65634
  );
65766
65635
  };
65767
- var TraitCardNode = React98__default.memo(TraitCardNodeInner);
65636
+ var TraitCardNode = React96__default.memo(TraitCardNodeInner);
65768
65637
  TraitCardNode.displayName = "TraitCardNode";
65769
65638
 
65770
65639
  // components/avl/organisms/FlowCanvas.tsx
@@ -65837,7 +65706,7 @@ function FlowCanvasInner({
65837
65706
  initialOrbital
65838
65707
  );
65839
65708
  const [expandedBehaviorAlias, setExpandedBehaviorAlias] = useState(void 0);
65840
- const screenSizeUserOverrideRef = React98__default.useRef(false);
65709
+ const screenSizeUserOverrideRef = React96__default.useRef(false);
65841
65710
  const [screenSize, setScreenSize] = useState(
65842
65711
  () => typeof window === "undefined" ? "laptop" : detectScreenSize(window.innerWidth)
65843
65712
  );
@@ -66221,7 +66090,7 @@ var ZoomBreadcrumb = ({
66221
66090
  if (eventName && band === "detail") {
66222
66091
  segments.push({ icon: "\u26A1", label: eventName });
66223
66092
  }
66224
- return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
66093
+ return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
66225
66094
  i > 0 && /* @__PURE__ */ jsx("span", { className: "opacity-40", children: ">" }),
66226
66095
  /* @__PURE__ */ jsx("span", { className: "opacity-60", children: seg.icon }),
66227
66096
  /* @__PURE__ */ jsx("span", { children: seg.label })
@@ -66562,7 +66431,7 @@ var EventWireOverlay = ({
66562
66431
  containerW,
66563
66432
  containerH
66564
66433
  }) => {
66565
- const ids = React98__default.useMemo(() => {
66434
+ const ids = React96__default.useMemo(() => {
66566
66435
  avlOczWireId += 1;
66567
66436
  return { arrow: `avl-ocz-wire-${avlOczWireId}-arrow` };
66568
66437
  }, []);
@@ -66929,7 +66798,7 @@ var AvlOrbitalsCosmicZoom = ({
66929
66798
  borderRadius: 6,
66930
66799
  border: `1px solid ${color}`
66931
66800
  },
66932
- children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React98__default.Fragment, { children: [
66801
+ children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React96__default.Fragment, { children: [
66933
66802
  i > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", style: { opacity: 0.5, color }, children: "/" }),
66934
66803
  i < breadcrumbs.length - 1 ? /* @__PURE__ */ jsx(
66935
66804
  Box,