@almadar/ui 5.79.2 → 5.81.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 (80) hide show
  1. package/dist/avl/index.cjs +1963 -1948
  2. package/dist/avl/index.css +3 -3
  3. package/dist/avl/index.js +754 -739
  4. package/dist/components/core/atoms/FlipContainer.d.ts +1 -1
  5. package/dist/components/core/molecules/Card.d.ts +1 -1
  6. package/dist/components/core/molecules/DataGrid.d.ts +1 -1
  7. package/dist/components/core/molecules/DataList.d.ts +1 -1
  8. package/dist/components/core/molecules/DocPagination.d.ts +1 -8
  9. package/dist/components/core/molecules/DocSearch.d.ts +1 -8
  10. package/dist/components/core/molecules/FlipCard.d.ts +1 -1
  11. package/dist/components/core/molecules/MapView.d.ts +1 -18
  12. package/dist/components/core/molecules/SortableList.d.ts +1 -1
  13. package/dist/components/core/molecules/TableView.d.ts +1 -1
  14. package/dist/components/core/molecules/WizardContainer.d.ts +7 -1
  15. package/dist/components/core/organisms/DataTable.d.ts +1 -1
  16. package/dist/components/core/organisms/DrawerSlot.d.ts +2 -0
  17. package/dist/components/core/organisms/ModalSlot.d.ts +2 -0
  18. package/dist/components/core/organisms/ToastSlot.d.ts +2 -0
  19. package/dist/components/core/organisms/debug/RuntimeDebugger.d.ts +1 -10
  20. package/dist/components/core/organisms/debug/tabs/EntitiesTab.d.ts +1 -2
  21. package/dist/components/core/organisms/debug/tabs/EventDispatcherTab.d.ts +1 -2
  22. package/dist/components/core/organisms/debug/tabs/EventFlowTab.d.ts +1 -6
  23. package/dist/components/core/organisms/debug/tabs/GuardsPanel.d.ts +1 -6
  24. package/dist/components/core/organisms/debug/tabs/ServerBridgeTab.d.ts +1 -12
  25. package/dist/components/core/organisms/debug/tabs/TicksTab.d.ts +1 -2
  26. package/dist/components/core/organisms/debug/tabs/TraitsTab.d.ts +1 -2
  27. package/dist/components/core/organisms/debug/tabs/TransitionTimeline.d.ts +1 -11
  28. package/dist/components/core/organisms/debug/tabs/VerificationTab.d.ts +1 -8
  29. package/dist/components/core/templates/CounterTemplate.d.ts +7 -0
  30. package/dist/components/game/2d/atoms/ActionButton.d.ts +4 -3
  31. package/dist/components/game/2d/atoms/ChoiceButton.d.ts +4 -3
  32. package/dist/components/game/2d/atoms/ComboCounter.d.ts +1 -2
  33. package/dist/components/game/2d/atoms/ControlButton.d.ts +1 -2
  34. package/dist/components/game/2d/atoms/DamageNumber.d.ts +1 -2
  35. package/dist/components/game/2d/atoms/DialogueBubble.d.ts +1 -2
  36. package/dist/components/game/2d/atoms/GameAudioToggle.d.ts +6 -1
  37. package/dist/components/game/2d/atoms/GameIcon.d.ts +1 -2
  38. package/dist/components/game/2d/atoms/HealthBar.d.ts +6 -2
  39. package/dist/components/game/2d/atoms/ItemSlot.d.ts +4 -3
  40. package/dist/components/game/2d/atoms/MiniMap.d.ts +6 -2
  41. package/dist/components/game/2d/atoms/ResourceCounter.d.ts +1 -2
  42. package/dist/components/game/2d/atoms/ScoreDisplay.d.ts +1 -2
  43. package/dist/components/game/2d/atoms/StatusEffect.d.ts +1 -2
  44. package/dist/components/game/2d/atoms/TimerDisplay.d.ts +4 -2
  45. package/dist/components/game/2d/atoms/TurnIndicator.d.ts +1 -2
  46. package/dist/components/game/2d/atoms/WaypointMarker.d.ts +1 -2
  47. package/dist/components/game/2d/molecules/ControlGrid.d.ts +3 -1
  48. package/dist/components/game/2d/molecules/GameHud.d.ts +1 -2
  49. package/dist/components/game/2d/molecules/GameMenu.d.ts +4 -8
  50. package/dist/components/game/2d/molecules/InventoryGrid.d.ts +1 -2
  51. package/dist/components/game/2d/molecules/ResourceBar.d.ts +1 -2
  52. package/dist/components/game/2d/molecules/StatBadge.d.ts +1 -2
  53. package/dist/components/game/2d/organisms/CityBuilderBoard.d.ts +2 -0
  54. package/dist/components/game/2d/organisms/PlatformerBoard.d.ts +3 -1
  55. package/dist/components/game/2d/organisms/RoguelikeBoard.d.ts +2 -0
  56. package/dist/components/game/2d/organisms/SequencerBoard.d.ts +5 -1
  57. package/dist/components/game/2d/organisms/SimulationControls.d.ts +25 -8
  58. package/dist/components/game/2d/organisms/TanksBoard.d.ts +4 -2
  59. package/dist/components/game/2d/organisms/TopDownShooterBoard.d.ts +2 -0
  60. package/dist/components/game/2d/organisms/TowerDefenseBoard.d.ts +2 -0
  61. package/dist/components/game/2d/organisms/TraitSlot.d.ts +5 -5
  62. package/dist/components/game/2d/templates/GameShell.d.ts +5 -0
  63. package/dist/components/game/2d/templates/GameTemplate.d.ts +3 -0
  64. package/dist/components/game/shared/lib/editorUtils.d.ts +8 -8
  65. package/dist/components/index.cjs +530 -483
  66. package/dist/components/index.css +3 -3
  67. package/dist/components/index.js +532 -485
  68. package/dist/hooks/useGitHub.d.ts +7 -7
  69. package/dist/marketing/index.cjs +2 -2
  70. package/dist/marketing/index.js +2 -2
  71. package/dist/providers/EventBusProvider.d.ts +1 -1
  72. package/dist/providers/SelectionProvider.d.ts +1 -1
  73. package/dist/providers/ServerBridge.d.ts +1 -1
  74. package/dist/providers/index.cjs +1826 -1811
  75. package/dist/providers/index.css +3 -3
  76. package/dist/providers/index.js +726 -711
  77. package/dist/runtime/index.cjs +1820 -1805
  78. package/dist/runtime/index.css +3 -3
  79. package/dist/runtime/index.js +730 -715
  80. package/package.json +1 -1
@@ -40,8 +40,8 @@ var core$1 = require('@almadar/core');
40
40
  var core = require('@dnd-kit/core');
41
41
  var sortable = require('@dnd-kit/sortable');
42
42
  var utilities = require('@dnd-kit/utilities');
43
- var patterns = require('@almadar/patterns');
44
43
  var react = require('@xyflow/react');
44
+ var patterns = require('@almadar/patterns');
45
45
  var reactQuery = require('@tanstack/react-query');
46
46
 
47
47
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -7972,6 +7972,38 @@ var init_Accordion = __esm({
7972
7972
  exports.Accordion.displayName = "Accordion";
7973
7973
  }
7974
7974
  });
7975
+ function GameIcon({ assetUrl, icon, size = "md", alt, className }) {
7976
+ const px = typeof size === "number" ? size : sizeMap[size];
7977
+ if (assetUrl?.url) {
7978
+ return /* @__PURE__ */ jsxRuntime.jsx(
7979
+ "img",
7980
+ {
7981
+ src: assetUrl.url,
7982
+ alt: alt ?? assetUrl.category ?? "",
7983
+ width: px,
7984
+ height: px,
7985
+ style: { imageRendering: "pixelated", objectFit: "contain", width: px, height: px },
7986
+ className: cn("flex-shrink-0", className)
7987
+ }
7988
+ );
7989
+ }
7990
+ const I = typeof icon === "string" ? resolveIcon(icon) : icon;
7991
+ return /* @__PURE__ */ jsxRuntime.jsx(I, { width: px, height: px, className: cn("flex-shrink-0", className) });
7992
+ }
7993
+ var sizeMap;
7994
+ var init_GameIcon = __esm({
7995
+ "components/game/2d/atoms/GameIcon.tsx"() {
7996
+ "use client";
7997
+ init_cn();
7998
+ init_Icon();
7999
+ sizeMap = {
8000
+ sm: 16,
8001
+ md: 24,
8002
+ lg: 32
8003
+ };
8004
+ GameIcon.displayName = "GameIcon";
8005
+ }
8006
+ });
7975
8007
  function ActionButton({
7976
8008
  assetUrl = DEFAULT_ASSET_URL,
7977
8009
  label = "Attack",
@@ -7982,18 +8014,23 @@ function ActionButton({
7982
8014
  size = "md",
7983
8015
  variant = "primary",
7984
8016
  onClick,
8017
+ action,
7985
8018
  className
7986
8019
  }) {
7987
- const sizes = sizeMap[size];
8020
+ const eventBus = useEventBus();
8021
+ const sizes = sizeMap2[size];
7988
8022
  const onCooldown = cooldown > 0;
7989
8023
  const isDisabled = disabled || onCooldown;
7990
8024
  const cooldownDeg = Math.round(cooldown * 360);
7991
8025
  return /* @__PURE__ */ jsxRuntime.jsxs(
7992
- "button",
8026
+ exports.Button,
7993
8027
  {
7994
- type: "button",
8028
+ variant: variant === "danger" ? "danger" : variant === "secondary" ? "secondary" : "primary",
7995
8029
  disabled: isDisabled,
7996
- onClick,
8030
+ onClick: () => {
8031
+ if (action) eventBus.emit(`UI:${action}`, {});
8032
+ onClick?.();
8033
+ },
7997
8034
  className: cn(
7998
8035
  "relative inline-flex items-center gap-1.5 rounded-interactive border font-medium overflow-hidden transition-colors duration-150",
7999
8036
  sizes.button,
@@ -8003,9 +8040,10 @@ function ActionButton({
8003
8040
  ),
8004
8041
  children: [
8005
8042
  onCooldown && /* @__PURE__ */ jsxRuntime.jsx(
8006
- "div",
8043
+ exports.Box,
8007
8044
  {
8008
- className: "absolute inset-0 bg-foreground/40 pointer-events-none",
8045
+ position: "absolute",
8046
+ className: "inset-0 bg-foreground/40 pointer-events-none",
8009
8047
  style: {
8010
8048
  clipPath: `conic-gradient(from 0deg, transparent ${360 - cooldownDeg}deg, black ${360 - cooldownDeg}deg)`,
8011
8049
  WebkitClipPath: `conic-gradient(from 0deg, transparent ${360 - cooldownDeg}deg, black ${360 - cooldownDeg}deg)`,
@@ -8013,27 +8051,18 @@ function ActionButton({
8013
8051
  }
8014
8052
  }
8015
8053
  ),
8016
- assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
8017
- "img",
8018
- {
8019
- src: assetUrl.url,
8020
- alt: "",
8021
- width: 16,
8022
- height: 16,
8023
- style: { imageRendering: "pixelated", objectFit: "contain" },
8024
- className: cn("flex-shrink-0", sizes.icon)
8025
- }
8026
- ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
8054
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 16, className: cn("flex-shrink-0", sizes.icon) }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
8027
8055
  const I = resolveIcon(icon);
8028
8056
  return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" }) : null;
8029
8057
  })() : /* @__PURE__ */ (() => {
8030
8058
  const I = icon;
8031
8059
  return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" });
8032
8060
  })() }) : null,
8033
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10", children: label }),
8061
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "relative z-10", children: label }),
8034
8062
  hotkey && /* @__PURE__ */ jsxRuntime.jsx(
8035
- "span",
8063
+ exports.Typography,
8036
8064
  {
8065
+ as: "span",
8037
8066
  className: cn(
8038
8067
  "absolute top-0.5 right-0.5 bg-foreground/30 text-primary-foreground rounded font-mono leading-tight",
8039
8068
  sizes.hotkey
@@ -8045,12 +8074,17 @@ function ActionButton({
8045
8074
  }
8046
8075
  );
8047
8076
  }
8048
- var sizeMap, variantStyles7, DEFAULT_ASSET_URL;
8077
+ var sizeMap2, variantStyles7, DEFAULT_ASSET_URL;
8049
8078
  var init_ActionButton = __esm({
8050
8079
  "components/game/2d/atoms/ActionButton.tsx"() {
8051
8080
  init_cn();
8052
8081
  init_Icon();
8053
- sizeMap = {
8082
+ init_useEventBus();
8083
+ init_Button();
8084
+ init_Box();
8085
+ init_Typography();
8086
+ init_GameIcon();
8087
+ sizeMap2 = {
8054
8088
  sm: { button: "h-button-sm px-3 text-xs", hotkey: "text-[9px] px-1", icon: "text-xs" },
8055
8089
  md: { button: "h-button-md px-4 text-sm", hotkey: "text-xs px-1.5", icon: "text-sm" },
8056
8090
  lg: { button: "h-button-lg px-5 text-base", hotkey: "text-xs px-2", icon: "text-base" }
@@ -8103,7 +8137,7 @@ function ActionTile({
8103
8137
  draggable: !disabled,
8104
8138
  onDragStart: handleDragStart,
8105
8139
  children: [
8106
- action.iconUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: action.iconUrl, alt: "", className: "w-8 h-8 object-contain" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8140
+ action.iconUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: action.iconUrl.url, alt: "", className: "w-8 h-8 object-contain" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8107
8141
  /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: cn(config.text, "text-foreground font-medium whitespace-nowrap"), children: action.name })
8108
8142
  ]
8109
8143
  }
@@ -8707,9 +8741,26 @@ function MiniMap({
8707
8741
  mapWidth = 100,
8708
8742
  mapHeight = 100,
8709
8743
  viewportRect = DEFAULT_VIEWPORT,
8710
- className
8744
+ className,
8745
+ tileAssets,
8746
+ unitAssets
8711
8747
  }) {
8712
8748
  const canvasRef = React79__namespace.useRef(null);
8749
+ const imgCacheRef = React79__namespace.useRef(/* @__PURE__ */ new Map());
8750
+ function loadImg(url) {
8751
+ const cached = imgCacheRef.current.get(url);
8752
+ if (cached) return cached.complete ? cached : null;
8753
+ const img = new Image();
8754
+ img.src = url;
8755
+ img.onload = () => {
8756
+ const canvas = canvasRef.current;
8757
+ if (!canvas) return;
8758
+ const ctx = canvas.getContext("2d");
8759
+ if (ctx) ctx.clearRect(0, 0, 0, 0);
8760
+ };
8761
+ imgCacheRef.current.set(url, img);
8762
+ return null;
8763
+ }
8713
8764
  React79__namespace.useEffect(() => {
8714
8765
  const canvas = canvasRef.current;
8715
8766
  if (!canvas) return;
@@ -8721,20 +8772,31 @@ function MiniMap({
8721
8772
  ctx.fillStyle = "#111";
8722
8773
  ctx.fillRect(0, 0, width, height);
8723
8774
  for (const tile of tiles) {
8724
- ctx.fillStyle = tile.color;
8725
- ctx.fillRect(
8726
- Math.floor(tile.x * scaleX2),
8727
- Math.floor(tile.y * scaleY2),
8728
- Math.max(1, Math.ceil(scaleX2)),
8729
- Math.max(1, Math.ceil(scaleY2))
8730
- );
8775
+ const tileAsset = tileAssets?.[tile.color] ?? tileAssets?.["default"];
8776
+ const tileImg = tileAsset ? loadImg(tileAsset.url) : null;
8777
+ const tx = Math.floor(tile.x * scaleX2);
8778
+ const ty = Math.floor(tile.y * scaleY2);
8779
+ const tw = Math.max(1, Math.ceil(scaleX2));
8780
+ const th = Math.max(1, Math.ceil(scaleY2));
8781
+ if (tileImg) {
8782
+ ctx.drawImage(tileImg, tx, ty, tw, th);
8783
+ } else {
8784
+ ctx.fillStyle = tile.color;
8785
+ ctx.fillRect(tx, ty, tw, th);
8786
+ }
8731
8787
  }
8732
8788
  for (const unit of units) {
8733
8789
  if (unit.isPlayer) continue;
8734
- ctx.fillStyle = unit.color;
8790
+ const unitAsset = unitAssets?.[unit.color] ?? unitAssets?.["default"];
8791
+ const unitImg = unitAsset ? loadImg(unitAsset.url) : null;
8735
8792
  const ux = Math.floor(unit.x * scaleX2) - 1;
8736
8793
  const uy = Math.floor(unit.y * scaleY2) - 1;
8737
- ctx.fillRect(ux, uy, 3, 3);
8794
+ if (unitImg) {
8795
+ ctx.drawImage(unitImg, ux, uy, 5, 5);
8796
+ } else {
8797
+ ctx.fillStyle = unit.color;
8798
+ ctx.fillRect(ux, uy, 3, 3);
8799
+ }
8738
8800
  }
8739
8801
  if (viewportRect) {
8740
8802
  ctx.strokeStyle = "#ffffff";
@@ -8746,7 +8808,7 @@ function MiniMap({
8746
8808
  Math.floor(viewportRect.h * scaleY2)
8747
8809
  );
8748
8810
  }
8749
- }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect]);
8811
+ }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect, tileAssets, unitAssets]);
8750
8812
  const scaleX = width / mapWidth;
8751
8813
  const scaleY = height / mapHeight;
8752
8814
  const playerUnit = units.find((u) => u.isPlayer);
@@ -8755,10 +8817,12 @@ function MiniMap({
8755
8817
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8756
8818
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: `@keyframes minimap-blink{0%,49%{opacity:1}50%,100%{opacity:0}}` }),
8757
8819
  /* @__PURE__ */ jsxRuntime.jsxs(
8758
- "div",
8820
+ exports.Box,
8759
8821
  {
8822
+ position: "relative",
8823
+ display: "inline-block",
8760
8824
  className: cn(
8761
- "relative inline-block border border-border/20 rounded-container",
8825
+ "border border-border/20 rounded-container",
8762
8826
  className
8763
8827
  ),
8764
8828
  children: [
@@ -8773,10 +8837,10 @@ function MiniMap({
8773
8837
  }
8774
8838
  ),
8775
8839
  playerLeft !== null && playerTop !== null && /* @__PURE__ */ jsxRuntime.jsx(
8776
- "div",
8840
+ exports.Box,
8777
8841
  {
8842
+ position: "absolute",
8778
8843
  style: {
8779
- position: "absolute",
8780
8844
  left: playerLeft,
8781
8845
  top: playerTop,
8782
8846
  width: 3,
@@ -8797,6 +8861,7 @@ var init_MiniMap = __esm({
8797
8861
  "components/game/2d/atoms/MiniMap.tsx"() {
8798
8862
  "use client";
8799
8863
  init_cn();
8864
+ init_Box();
8800
8865
  DEFAULT_TILES = [
8801
8866
  { x: 10, y: 10, color: "#4ade80" },
8802
8867
  { x: 20, y: 15, color: "#4ade80" },
@@ -8823,14 +8888,17 @@ function HealthBar({
8823
8888
  labelSuffix,
8824
8889
  size = "md",
8825
8890
  className,
8826
- animated = true
8891
+ animated = true,
8892
+ frameAsset,
8893
+ fillAsset
8827
8894
  }) {
8828
- const sizes = sizeMap2[size];
8895
+ const sizes = sizeMap3[size];
8829
8896
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
8830
8897
  if (format === "hearts") {
8831
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center gap-1", className), children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
8832
- "span",
8898
+ return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("flex items-center gap-1", className), children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
8899
+ exports.Box,
8833
8900
  {
8901
+ as: "span",
8834
8902
  className: cn(animated && "transition-transform hover:scale-110"),
8835
8903
  children: heartIcon(i < current, sizes.heart)
8836
8904
  },
@@ -8839,33 +8907,42 @@ function HealthBar({
8839
8907
  }
8840
8908
  if (format === "bar") {
8841
8909
  return /* @__PURE__ */ jsxRuntime.jsx(
8842
- "div",
8910
+ exports.Box,
8843
8911
  {
8912
+ position: "relative",
8913
+ overflow: "hidden",
8844
8914
  className: cn(
8845
- "relative overflow-hidden rounded-full bg-muted",
8915
+ "rounded-full",
8916
+ !frameAsset && "bg-muted",
8846
8917
  sizes.bar,
8847
8918
  "w-24",
8848
8919
  className
8849
8920
  ),
8921
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8850
8922
  children: /* @__PURE__ */ jsxRuntime.jsx(
8851
- "div",
8923
+ exports.Box,
8852
8924
  {
8925
+ position: "absolute",
8853
8926
  className: cn(
8854
- "absolute inset-y-0 left-0 rounded-full",
8855
- percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error",
8927
+ "inset-y-0 left-0 rounded-full",
8928
+ !fillAsset && (percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error"),
8856
8929
  animated && "transition-all duration-300"
8857
8930
  ),
8858
- style: { width: `${percentage}%` }
8931
+ style: {
8932
+ width: `${percentage}%`,
8933
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8934
+ }
8859
8935
  }
8860
8936
  )
8861
8937
  }
8862
8938
  );
8863
8939
  }
8864
8940
  if (format === "progress") {
8865
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2", className), children: [
8941
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn("flex items-center gap-2", className), children: [
8866
8942
  level != null && /* @__PURE__ */ jsxRuntime.jsxs(
8867
- "span",
8943
+ exports.Typography,
8868
8944
  {
8945
+ as: "span",
8869
8946
  className: cn(
8870
8947
  "flex-shrink-0 rounded-interactive font-bold",
8871
8948
  "bg-accent text-accent-foreground border border-accent",
@@ -8877,28 +8954,35 @@ function HealthBar({
8877
8954
  ]
8878
8955
  }
8879
8956
  ),
8880
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [
8957
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex-1 flex flex-col gap-0.5", children: [
8881
8958
  /* @__PURE__ */ jsxRuntime.jsx(
8882
- "div",
8959
+ exports.Box,
8883
8960
  {
8961
+ position: "relative",
8884
8962
  className: cn(
8885
- "relative w-full overflow-hidden rounded-full bg-muted border border-muted",
8963
+ "w-full overflow-hidden rounded-full",
8964
+ !frameAsset && "bg-muted border border-muted",
8886
8965
  sizes.bar
8887
8966
  ),
8967
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8888
8968
  children: /* @__PURE__ */ jsxRuntime.jsx(
8889
- "div",
8969
+ exports.Box,
8890
8970
  {
8971
+ position: "absolute",
8891
8972
  className: cn(
8892
- "absolute inset-y-0 left-0 rounded-full",
8893
- "bg-gradient-to-r from-accent to-info",
8973
+ "inset-y-0 left-0 rounded-full",
8974
+ !fillAsset && "bg-gradient-to-r from-accent to-info",
8894
8975
  animated && "transition-all duration-500 ease-out"
8895
8976
  ),
8896
- style: { width: `${percentage}%` }
8977
+ style: {
8978
+ width: `${percentage}%`,
8979
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8980
+ }
8897
8981
  }
8898
8982
  )
8899
8983
  }
8900
8984
  ),
8901
- showLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-foreground/70 tabular-nums", sizes.label), children: [
8985
+ showLabel && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: cn("text-foreground/70 tabular-nums", sizes.label), children: [
8902
8986
  current,
8903
8987
  " / ",
8904
8988
  max,
@@ -8907,16 +8991,18 @@ function HealthBar({
8907
8991
  ] })
8908
8992
  ] });
8909
8993
  }
8910
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-mono font-bold", sizes.text, className), children: [
8994
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: cn("font-mono font-bold", sizes.text, className), children: [
8911
8995
  current,
8912
8996
  "/",
8913
8997
  max
8914
8998
  ] });
8915
8999
  }
8916
- var heartIcon, sizeMap2;
9000
+ var heartIcon, sizeMap3;
8917
9001
  var init_HealthBar = __esm({
8918
9002
  "components/game/2d/atoms/HealthBar.tsx"() {
8919
9003
  init_cn();
9004
+ init_Box();
9005
+ init_Typography();
8920
9006
  heartIcon = (filled, size) => /* @__PURE__ */ jsxRuntime.jsx(
8921
9007
  "svg",
8922
9008
  {
@@ -8928,7 +9014,7 @@ var init_HealthBar = __esm({
8928
9014
  children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })
8929
9015
  }
8930
9016
  );
8931
- sizeMap2 = {
9017
+ sizeMap3 = {
8932
9018
  sm: { heart: "w-4 h-4", bar: "h-2", text: "text-sm", label: "text-xs", badge: "text-xs px-1.5 py-0.5" },
8933
9019
  md: { heart: "w-6 h-6", bar: "h-3", text: "text-base", label: "text-xs", badge: "text-xs px-2 py-0.5" },
8934
9020
  lg: { heart: "w-8 h-8", bar: "h-4", text: "text-lg", label: "text-sm", badge: "text-sm px-2.5 py-1" }
@@ -10716,10 +10802,11 @@ function Canvas2D({
10716
10802
  }
10717
10803
  }
10718
10804
  ),
10719
- process.env.NODE_ENV !== "production" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-game-actions": "", className: "sr-only", "aria-hidden": "true", children: [
10805
+ process.env.NODE_ENV !== "production" && /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { "data-game-actions": "", className: "sr-only", "aria-hidden": "true", children: [
10720
10806
  tileClickEvent && /* @__PURE__ */ jsxRuntime.jsx(
10721
- "button",
10807
+ exports.Button,
10722
10808
  {
10809
+ variant: "ghost",
10723
10810
  "data-event": tileClickEvent,
10724
10811
  "data-x": "0",
10725
10812
  "data-y": "0",
@@ -10728,8 +10815,9 @@ function Canvas2D({
10728
10815
  }
10729
10816
  ),
10730
10817
  unitClickEvent && units && units.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
10731
- "button",
10818
+ exports.Button,
10732
10819
  {
10820
+ variant: "ghost",
10733
10821
  "data-event": unitClickEvent,
10734
10822
  "data-unit-id": units[0].id,
10735
10823
  onClick: () => eventBus.emit(`UI:${unitClickEvent}`, { unitId: units[0].id }),
@@ -10738,15 +10826,17 @@ function Canvas2D({
10738
10826
  )
10739
10827
  ] }),
10740
10828
  unitOverlays.map(({ unit, screenX, screenY }) => /* @__PURE__ */ jsxRuntime.jsxs(
10741
- "div",
10829
+ exports.Box,
10742
10830
  {
10743
- className: "absolute pointer-events-none",
10831
+ position: "absolute",
10832
+ className: "pointer-events-none",
10744
10833
  style: { left: Math.round(screenX), top: Math.round(screenY), transform: "translate(-50%, 0)", zIndex: 5 },
10745
10834
  children: [
10746
10835
  unit.name && /* @__PURE__ */ jsxRuntime.jsx(
10747
- "div",
10836
+ exports.Typography,
10748
10837
  {
10749
- className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap",
10838
+ as: "span",
10839
+ className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap block",
10750
10840
  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)" },
10751
10841
  children: unit.name
10752
10842
  }
@@ -10756,7 +10846,7 @@ function Canvas2D({
10756
10846
  },
10757
10847
  unit.id
10758
10848
  )),
10759
- showMinimap && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-2 right-2 pointer-events-none", style: { zIndex: 10 }, children: /* @__PURE__ */ jsxRuntime.jsx(
10849
+ showMinimap && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { position: "absolute", className: "bottom-2 right-2 pointer-events-none", style: { zIndex: 10 }, children: /* @__PURE__ */ jsxRuntime.jsx(
10760
10850
  MiniMap,
10761
10851
  {
10762
10852
  tiles: miniMapTiles,
@@ -10778,6 +10868,7 @@ var init_Canvas2D = __esm({
10778
10868
  init_cn();
10779
10869
  init_useEventBus();
10780
10870
  init_Box();
10871
+ init_Button();
10781
10872
  init_Stack();
10782
10873
  init_Icon();
10783
10874
  init_Typography();
@@ -12675,9 +12766,9 @@ var init_BiologyCanvas = __esm({
12675
12766
  }
12676
12767
  });
12677
12768
 
12678
- // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
12769
+ // node_modules/katex/dist/katex.min.css
12679
12770
  var init_katex_min = __esm({
12680
- "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
12771
+ "node_modules/katex/dist/katex.min.css"() {
12681
12772
  }
12682
12773
  });
12683
12774
  exports.Tabs = void 0;
@@ -17155,38 +17246,6 @@ var init_Breadcrumb = __esm({
17155
17246
  exports.Breadcrumb.displayName = "Breadcrumb";
17156
17247
  }
17157
17248
  });
17158
- function GameIcon({ assetUrl, icon, size = "md", alt, className }) {
17159
- const px = typeof size === "number" ? size : sizeMap3[size];
17160
- if (assetUrl?.url) {
17161
- return /* @__PURE__ */ jsxRuntime.jsx(
17162
- "img",
17163
- {
17164
- src: assetUrl.url,
17165
- alt: alt ?? assetUrl.category ?? "",
17166
- width: px,
17167
- height: px,
17168
- style: { imageRendering: "pixelated", objectFit: "contain", width: px, height: px },
17169
- className: cn("flex-shrink-0", className)
17170
- }
17171
- );
17172
- }
17173
- const I = typeof icon === "string" ? resolveIcon(icon) : icon;
17174
- return /* @__PURE__ */ jsxRuntime.jsx(I, { width: px, height: px, className: cn("flex-shrink-0", className) });
17175
- }
17176
- var sizeMap3;
17177
- var init_GameIcon = __esm({
17178
- "components/game/2d/atoms/GameIcon.tsx"() {
17179
- "use client";
17180
- init_cn();
17181
- init_Icon();
17182
- sizeMap3 = {
17183
- sm: 16,
17184
- md: 24,
17185
- lg: 32
17186
- };
17187
- GameIcon.displayName = "GameIcon";
17188
- }
17189
- });
17190
17249
  function BuilderBoard({
17191
17250
  entity,
17192
17251
  completeEvent = "PUZZLE_COMPLETE",
@@ -19018,9 +19077,9 @@ function GameCard({
19018
19077
  }, [disabled, id, onClick, clickEvent, eventBus]);
19019
19078
  const artPx = artPxMap[size];
19020
19079
  return /* @__PURE__ */ jsxRuntime.jsxs(
19021
- "button",
19080
+ exports.Button,
19022
19081
  {
19023
- type: "button",
19082
+ variant: "ghost",
19024
19083
  onClick: handleClick,
19025
19084
  disabled,
19026
19085
  title: name,
@@ -19034,8 +19093,9 @@ function GameCard({
19034
19093
  ),
19035
19094
  children: [
19036
19095
  cost != null && /* @__PURE__ */ jsxRuntime.jsx(
19037
- "span",
19096
+ exports.Typography,
19038
19097
  {
19098
+ as: "span",
19039
19099
  className: cn(
19040
19100
  "absolute -top-2 -left-2 flex items-center justify-center",
19041
19101
  "min-w-[22px] h-[22px] rounded-full px-1",
@@ -19044,17 +19104,7 @@ function GameCard({
19044
19104
  children: cost
19045
19105
  }
19046
19106
  ),
19047
- /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-1 flex items-center justify-center w-full", children: art ? /* @__PURE__ */ jsxRuntime.jsx(
19048
- "img",
19049
- {
19050
- src: art.url,
19051
- alt: name ?? id,
19052
- width: artPx,
19053
- height: artPx,
19054
- style: { imageRendering: "pixelated", objectFit: "contain" },
19055
- className: "flex-shrink-0"
19056
- }
19057
- ) : /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "rounded bg-muted/40", style: { width: artPx, height: artPx } }) }),
19107
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-1 flex items-center justify-center w-full", children: art ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: art, icon: "image", size: artPx, alt: name ?? id, className: "flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "rounded bg-muted/40", style: { width: artPx, height: artPx } }) }),
19058
19108
  name != null && /* @__PURE__ */ jsxRuntime.jsx(
19059
19109
  exports.Typography,
19060
19110
  {
@@ -19064,8 +19114,8 @@ function GameCard({
19064
19114
  }
19065
19115
  ),
19066
19116
  (attack != null || defense != null) && /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex w-full items-center justify-between px-0.5 text-[10px] font-bold leading-none", children: [
19067
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-error", children: attack != null ? `\u2694${attack}` : "" }),
19068
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-info", children: defense != null ? `\u{1F6E1}${defense}` : "" })
19117
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-error", children: attack != null ? `\u2694${attack}` : "" }),
19118
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-info", children: defense != null ? `\u{1F6E1}${defense}` : "" })
19069
19119
  ] })
19070
19120
  ]
19071
19121
  }
@@ -19078,7 +19128,9 @@ var init_GameCard = __esm({
19078
19128
  init_cn();
19079
19129
  init_useEventBus();
19080
19130
  init_Box();
19131
+ init_Button();
19081
19132
  init_Typography();
19133
+ init_GameIcon();
19082
19134
  cardSizeMap = {
19083
19135
  sm: "w-16 h-24",
19084
19136
  md: "w-20 h-28",
@@ -21484,14 +21536,19 @@ function ChoiceButton({
21484
21536
  disabled = false,
21485
21537
  selected = false,
21486
21538
  onClick,
21539
+ action,
21487
21540
  className
21488
21541
  }) {
21542
+ const eventBus = useEventBus();
21489
21543
  return /* @__PURE__ */ jsxRuntime.jsxs(
21490
- "button",
21544
+ exports.Button,
21491
21545
  {
21492
- type: "button",
21546
+ variant: "ghost",
21493
21547
  disabled,
21494
- onClick,
21548
+ onClick: () => {
21549
+ if (action) eventBus.emit(`UI:${action}`, {});
21550
+ onClick?.();
21551
+ },
21495
21552
  className: cn(
21496
21553
  "w-full text-left px-4 py-2.5 rounded-interactive border transition-all duration-150",
21497
21554
  "flex items-center gap-2",
@@ -21501,8 +21558,9 @@ function ChoiceButton({
21501
21558
  ),
21502
21559
  children: [
21503
21560
  index !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(
21504
- "span",
21561
+ exports.Typography,
21505
21562
  {
21563
+ as: "span",
21506
21564
  className: cn(
21507
21565
  "flex-shrink-0 font-mono font-bold text-sm",
21508
21566
  selected ? "text-accent" : "text-muted-foreground"
@@ -21513,24 +21571,14 @@ function ChoiceButton({
21513
21571
  ]
21514
21572
  }
21515
21573
  ),
21516
- assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
21517
- "img",
21518
- {
21519
- src: assetUrl.url,
21520
- alt: "",
21521
- width: 16,
21522
- height: 16,
21523
- style: { imageRendering: "pixelated", objectFit: "contain" },
21524
- className: "flex-shrink-0"
21525
- }
21526
- ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
21574
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 16, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
21527
21575
  const I = resolveIcon(icon);
21528
21576
  return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" }) : null;
21529
21577
  })() : /* @__PURE__ */ (() => {
21530
21578
  const I = icon;
21531
21579
  return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" });
21532
21580
  })() }) : null,
21533
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm leading-snug", children: text })
21581
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-sm leading-snug", children: text })
21534
21582
  ]
21535
21583
  }
21536
21584
  );
@@ -21539,6 +21587,11 @@ var init_ChoiceButton = __esm({
21539
21587
  "components/game/2d/atoms/ChoiceButton.tsx"() {
21540
21588
  init_cn();
21541
21589
  init_Icon();
21590
+ init_useEventBus();
21591
+ init_Button();
21592
+ init_Box();
21593
+ init_Typography();
21594
+ init_GameIcon();
21542
21595
  ChoiceButton.displayName = "ChoiceButton";
21543
21596
  }
21544
21597
  });
@@ -22216,7 +22269,7 @@ function ComboCounter({
22216
22269
  const sizes = sizeMap4[size];
22217
22270
  if (combo <= 0) return null;
22218
22271
  return /* @__PURE__ */ jsxRuntime.jsxs(
22219
- "div",
22272
+ exports.Box,
22220
22273
  {
22221
22274
  className: cn(
22222
22275
  "inline-flex flex-col items-center justify-center",
@@ -22226,24 +22279,14 @@ function ComboCounter({
22226
22279
  className
22227
22280
  ),
22228
22281
  children: [
22229
- assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
22230
- "img",
22231
- {
22232
- src: assetUrl.url,
22233
- alt: "combo",
22234
- width: 24,
22235
- height: 24,
22236
- style: { imageRendering: "pixelated", objectFit: "contain" },
22237
- className: "flex-shrink-0 mb-0.5"
22238
- }
22239
- ),
22240
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-black tabular-nums leading-none", sizes.combo, getComboIntensity(combo)), children: combo }),
22241
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-bold uppercase tracking-wider text-muted-foreground", sizes.label), children: "combo" }),
22242
- multiplier != null && multiplier > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-bold text-warning tabular-nums", sizes.multiplier), children: [
22282
+ assetUrl && /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 24, className: "flex-shrink-0 mb-0.5" }),
22283
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: cn("font-black tabular-nums leading-none", sizes.combo, getComboIntensity(combo)), children: combo }),
22284
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: cn("font-bold uppercase tracking-wider text-muted-foreground", sizes.label), children: "combo" }),
22285
+ multiplier != null && multiplier > 1 && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: cn("font-bold text-warning tabular-nums", sizes.multiplier), children: [
22243
22286
  "x",
22244
22287
  multiplier.toFixed(1)
22245
22288
  ] }),
22246
- streak != null && streak > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-muted-foreground tabular-nums", sizes.label), children: [
22289
+ streak != null && streak > 0 && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: cn("text-muted-foreground tabular-nums", sizes.label), children: [
22247
22290
  streak,
22248
22291
  " streak"
22249
22292
  ] })
@@ -22255,6 +22298,9 @@ var DEFAULT_ASSET_URL2, sizeMap4;
22255
22298
  var init_ComboCounter = __esm({
22256
22299
  "components/game/2d/atoms/ComboCounter.tsx"() {
22257
22300
  init_cn();
22301
+ init_Box();
22302
+ init_Typography();
22303
+ init_GameIcon();
22258
22304
  DEFAULT_ASSET_URL2 = {
22259
22305
  url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
22260
22306
  role: "effect",
@@ -22504,9 +22550,9 @@ function ControlButton({
22504
22550
  [isPressed, releaseEvent, eventBus, onRelease]
22505
22551
  );
22506
22552
  return /* @__PURE__ */ jsxRuntime.jsx(
22507
- "button",
22553
+ exports.Button,
22508
22554
  {
22509
- type: "button",
22555
+ variant,
22510
22556
  disabled,
22511
22557
  onPointerDown: handlePointerDown,
22512
22558
  onPointerUp: handlePointerUp,
@@ -22524,23 +22570,13 @@ function ControlButton({
22524
22570
  disabled && "opacity-50 cursor-not-allowed",
22525
22571
  className
22526
22572
  ),
22527
- children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
22528
- "img",
22529
- {
22530
- src: assetUrl.url,
22531
- alt: "",
22532
- width: 24,
22533
- height: 24,
22534
- style: { imageRendering: "pixelated", objectFit: "contain" },
22535
- className: "flex-shrink-0"
22536
- }
22537
- ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
22573
+ children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 24, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
22538
22574
  const I = resolveIcon(icon);
22539
22575
  return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-6 h-6" }) : null;
22540
22576
  })() : icon : /* @__PURE__ */ (() => {
22541
22577
  const I = icon;
22542
22578
  return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-6 h-6" });
22543
- })() }) : label ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }) : null
22579
+ })() }) : label ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", children: label }) : null
22544
22580
  }
22545
22581
  );
22546
22582
  }
@@ -22551,6 +22587,10 @@ var init_ControlButton = __esm({
22551
22587
  init_cn();
22552
22588
  init_useEventBus();
22553
22589
  init_Icon();
22590
+ init_Button();
22591
+ init_Box();
22592
+ init_Typography();
22593
+ init_GameIcon();
22554
22594
  sizeMap5 = {
22555
22595
  sm: "w-10 h-10 text-sm",
22556
22596
  md: "w-14 h-14 text-base",
@@ -22584,6 +22624,7 @@ function ControlGrid({
22584
22624
  actionEvent,
22585
22625
  onDirection,
22586
22626
  directionEvent,
22627
+ directionAssets,
22587
22628
  size = "md",
22588
22629
  disabled,
22589
22630
  className
@@ -22623,7 +22664,8 @@ function ControlGrid({
22623
22664
  const dir = (d) => /* @__PURE__ */ jsxRuntime.jsx(
22624
22665
  ControlButton,
22625
22666
  {
22626
- icon: arrowIcons[d],
22667
+ icon: directionAssets?.[d] ? void 0 : arrowIcons[d],
22668
+ assetUrl: directionAssets?.[d],
22627
22669
  size: sizeKey[size],
22628
22670
  variant: "secondary",
22629
22671
  pressed: active.has(d),
@@ -22633,22 +22675,22 @@ function ControlGrid({
22633
22675
  },
22634
22676
  d
22635
22677
  );
22636
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("inline-grid grid-cols-3", ds.gap, ds.container, className), children: [
22637
- /* @__PURE__ */ jsxRuntime.jsx("div", {}),
22678
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn("inline-grid grid-cols-3", ds.gap, ds.container, className), children: [
22679
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {}),
22638
22680
  dir("up"),
22639
- /* @__PURE__ */ jsxRuntime.jsx("div", {}),
22681
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {}),
22640
22682
  dir("left"),
22641
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-6 h-6 rounded-interactive bg-muted border-2 border-muted-foreground" }) }),
22683
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "w-6 h-6 rounded-interactive bg-muted border-2 border-muted-foreground" }) }),
22642
22684
  dir("right"),
22643
- /* @__PURE__ */ jsxRuntime.jsx("div", {}),
22685
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {}),
22644
22686
  dir("down"),
22645
- /* @__PURE__ */ jsxRuntime.jsx("div", {})
22687
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {})
22646
22688
  ] });
22647
22689
  }
22648
22690
  if (layout === "diamond" && buttons.length === 4) {
22649
22691
  const [top, right, bottom, left] = buttons;
22650
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(layoutClass.diamond, className), children: [
22651
- /* @__PURE__ */ jsxRuntime.jsx("div", {}),
22692
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn(layoutClass.diamond, className), children: [
22693
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {}),
22652
22694
  /* @__PURE__ */ jsxRuntime.jsx(
22653
22695
  ControlButton,
22654
22696
  {
@@ -22663,7 +22705,7 @@ function ControlGrid({
22663
22705
  disabled
22664
22706
  }
22665
22707
  ),
22666
- /* @__PURE__ */ jsxRuntime.jsx("div", {}),
22708
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {}),
22667
22709
  /* @__PURE__ */ jsxRuntime.jsx(
22668
22710
  ControlButton,
22669
22711
  {
@@ -22678,7 +22720,7 @@ function ControlGrid({
22678
22720
  disabled
22679
22721
  }
22680
22722
  ),
22681
- /* @__PURE__ */ jsxRuntime.jsx("div", {}),
22723
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {}),
22682
22724
  /* @__PURE__ */ jsxRuntime.jsx(
22683
22725
  ControlButton,
22684
22726
  {
@@ -22693,7 +22735,7 @@ function ControlGrid({
22693
22735
  disabled
22694
22736
  }
22695
22737
  ),
22696
- /* @__PURE__ */ jsxRuntime.jsx("div", {}),
22738
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {}),
22697
22739
  /* @__PURE__ */ jsxRuntime.jsx(
22698
22740
  ControlButton,
22699
22741
  {
@@ -22708,10 +22750,10 @@ function ControlGrid({
22708
22750
  disabled
22709
22751
  }
22710
22752
  ),
22711
- /* @__PURE__ */ jsxRuntime.jsx("div", {})
22753
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, {})
22712
22754
  ] });
22713
22755
  }
22714
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(layoutClass[layout], className), children: buttons.map((button) => /* @__PURE__ */ jsxRuntime.jsx(
22756
+ return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn(layoutClass[layout], className), children: buttons.map((button) => /* @__PURE__ */ jsxRuntime.jsx(
22715
22757
  ControlButton,
22716
22758
  {
22717
22759
  icon: button.icon,
@@ -22733,6 +22775,7 @@ var init_ControlGrid = __esm({
22733
22775
  "use client";
22734
22776
  init_cn();
22735
22777
  init_useEventBus();
22778
+ init_Box();
22736
22779
  init_ControlButton();
22737
22780
  sizeKey = { sm: "sm", md: "md", lg: "lg" };
22738
22781
  layoutClass = {
@@ -22764,6 +22807,8 @@ function CounterMinimal({
22764
22807
  size = "md",
22765
22808
  onDecrement,
22766
22809
  onIncrement,
22810
+ decrementEvent,
22811
+ incrementEvent,
22767
22812
  className
22768
22813
  }) {
22769
22814
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22774,6 +22819,7 @@ function CounterMinimal({
22774
22819
  {
22775
22820
  variant: "secondary",
22776
22821
  size: sizeStyles8[size].button,
22822
+ action: decrementEvent,
22777
22823
  onClick: onDecrement,
22778
22824
  disabled: resolved.decrementDisabled,
22779
22825
  icon: "minus",
@@ -22796,6 +22842,7 @@ function CounterMinimal({
22796
22842
  {
22797
22843
  variant: "secondary",
22798
22844
  size: sizeStyles8[size].button,
22845
+ action: incrementEvent,
22799
22846
  onClick: onIncrement,
22800
22847
  disabled: resolved.incrementDisabled,
22801
22848
  icon: "plus",
@@ -22812,6 +22859,9 @@ function CounterStandard({
22812
22859
  onDecrement,
22813
22860
  onIncrement,
22814
22861
  onReset,
22862
+ decrementEvent,
22863
+ incrementEvent,
22864
+ resetEvent,
22815
22865
  className
22816
22866
  }) {
22817
22867
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22842,6 +22892,7 @@ function CounterStandard({
22842
22892
  {
22843
22893
  variant: "secondary",
22844
22894
  size: sizeStyles8[size].button,
22895
+ action: decrementEvent,
22845
22896
  onClick: onDecrement,
22846
22897
  disabled: resolved.decrementDisabled,
22847
22898
  icon: "minus"
@@ -22852,6 +22903,7 @@ function CounterStandard({
22852
22903
  {
22853
22904
  variant: "primary",
22854
22905
  size: sizeStyles8[size].button,
22906
+ action: incrementEvent,
22855
22907
  onClick: onIncrement,
22856
22908
  disabled: resolved.incrementDisabled,
22857
22909
  icon: "plus"
@@ -22863,6 +22915,7 @@ function CounterStandard({
22863
22915
  {
22864
22916
  variant: "ghost",
22865
22917
  size: "sm",
22918
+ action: resetEvent,
22866
22919
  onClick: onReset,
22867
22920
  icon: "rotate-ccw",
22868
22921
  children: "Reset"
@@ -22878,6 +22931,9 @@ function CounterFull({
22878
22931
  onDecrement,
22879
22932
  onIncrement,
22880
22933
  onReset,
22934
+ decrementEvent,
22935
+ incrementEvent,
22936
+ resetEvent,
22881
22937
  className
22882
22938
  }) {
22883
22939
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22911,6 +22967,7 @@ function CounterFull({
22911
22967
  {
22912
22968
  variant: "secondary",
22913
22969
  size: sizeStyles8[size].button,
22970
+ action: decrementEvent,
22914
22971
  onClick: onDecrement,
22915
22972
  disabled: resolved.decrementDisabled,
22916
22973
  icon: "minus",
@@ -22922,6 +22979,7 @@ function CounterFull({
22922
22979
  {
22923
22980
  variant: "primary",
22924
22981
  size: sizeStyles8[size].button,
22982
+ action: incrementEvent,
22925
22983
  onClick: onIncrement,
22926
22984
  disabled: resolved.incrementDisabled,
22927
22985
  icon: "plus",
@@ -22934,6 +22992,7 @@ function CounterFull({
22934
22992
  {
22935
22993
  variant: "ghost",
22936
22994
  size: "sm",
22995
+ action: resetEvent,
22937
22996
  onClick: onReset,
22938
22997
  icon: "rotate-ccw",
22939
22998
  children: "Reset to 0"
@@ -22981,8 +23040,9 @@ function DamageNumber({
22981
23040
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
22982
23041
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: floatKeyframes }),
22983
23042
  /* @__PURE__ */ jsxRuntime.jsxs(
22984
- "span",
23043
+ exports.Typography,
22985
23044
  {
23045
+ as: "span",
22986
23046
  className: cn(
22987
23047
  "inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
22988
23048
  sizeMap6[size],
@@ -22991,17 +23051,7 @@ function DamageNumber({
22991
23051
  ),
22992
23052
  style: { animation: "damageFloat 1s ease-out forwards" },
22993
23053
  children: [
22994
- assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
22995
- "img",
22996
- {
22997
- src: assetUrl.url,
22998
- alt: "",
22999
- width: 14,
23000
- height: 14,
23001
- style: { imageRendering: "pixelated", objectFit: "contain" },
23002
- className: "flex-shrink-0"
23003
- }
23004
- ),
23054
+ assetUrl && /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 14, className: "flex-shrink-0" }),
23005
23055
  displayText
23006
23056
  ]
23007
23057
  }
@@ -23012,6 +23062,8 @@ var sizeMap6, typeStyles, floatKeyframes, DEFAULT_ASSET_URL4;
23012
23062
  var init_DamageNumber = __esm({
23013
23063
  "components/game/2d/atoms/DamageNumber.tsx"() {
23014
23064
  init_cn();
23065
+ init_Typography();
23066
+ init_GameIcon();
23015
23067
  sizeMap6 = {
23016
23068
  sm: "text-sm",
23017
23069
  md: "text-lg",
@@ -29373,7 +29425,7 @@ function ScoreDisplay({
29373
29425
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof score === "number" && !Number.isNaN(score) ? score : 0;
29374
29426
  const formattedValue = new Intl.NumberFormat(locale).format(resolvedValue);
29375
29427
  return /* @__PURE__ */ jsxRuntime.jsxs(
29376
- "div",
29428
+ exports.Box,
29377
29429
  {
29378
29430
  className: cn(
29379
29431
  "flex items-center gap-2 font-bold",
@@ -29381,19 +29433,9 @@ function ScoreDisplay({
29381
29433
  className
29382
29434
  ),
29383
29435
  children: [
29384
- assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
29385
- "img",
29386
- {
29387
- src: assetUrl.url,
29388
- alt: "",
29389
- width: 20,
29390
- height: 20,
29391
- style: { imageRendering: "pixelated", objectFit: "contain" },
29392
- className: "flex-shrink-0"
29393
- }
29394
- ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
29395
- label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
29396
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: formattedValue })
29436
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 20, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
29437
+ label && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground", children: label }),
29438
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "tabular-nums", children: formattedValue })
29397
29439
  ]
29398
29440
  }
29399
29441
  );
@@ -29403,6 +29445,9 @@ var init_ScoreDisplay = __esm({
29403
29445
  "components/game/2d/atoms/ScoreDisplay.tsx"() {
29404
29446
  init_cn();
29405
29447
  init_Icon();
29448
+ init_Box();
29449
+ init_Typography();
29450
+ init_GameIcon();
29406
29451
  sizeMap8 = {
29407
29452
  sm: "text-sm",
29408
29453
  md: "text-lg",
@@ -29463,12 +29508,12 @@ function Sprite({
29463
29508
  onClick?.();
29464
29509
  };
29465
29510
  return /* @__PURE__ */ jsxRuntime.jsx(
29466
- "div",
29511
+ exports.Box,
29467
29512
  {
29513
+ position: "absolute",
29468
29514
  className,
29469
29515
  onClick: action || onClick ? handleClick : void 0,
29470
29516
  style: {
29471
- position: "absolute",
29472
29517
  width: frameWidth,
29473
29518
  height: frameHeight,
29474
29519
  backgroundImage: `url(${spritesheet.url})`,
@@ -29524,6 +29569,7 @@ var init_Sprite = __esm({
29524
29569
  "components/game/2d/atoms/Sprite.tsx"() {
29525
29570
  "use client";
29526
29571
  init_useEventBus();
29572
+ init_Box();
29527
29573
  init_spriteAnimation();
29528
29574
  DEFAULT_SPRITESHEET = {
29529
29575
  url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
@@ -29560,17 +29606,7 @@ function StateIndicator({
29560
29606
  className
29561
29607
  ),
29562
29608
  children: [
29563
- /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
29564
- "img",
29565
- {
29566
- src: assetUrl.url,
29567
- alt: displayLabel,
29568
- width: 16,
29569
- height: 16,
29570
- style: { imageRendering: "pixelated", objectFit: "contain" },
29571
- className: "flex-shrink-0"
29572
- }
29573
- ) : typeof config.icon === "string" ? /^[a-zA-Z0-9-]+$/.test(config.icon) ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: config.icon }) : config.icon : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: config.icon }) }),
29609
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 16, alt: displayLabel, className: "flex-shrink-0" }) : typeof config.icon === "string" ? /^[a-zA-Z0-9-]+$/.test(config.icon) ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: config.icon }) : config.icon : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: config.icon }) }),
29574
29610
  /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", children: displayLabel })
29575
29611
  ]
29576
29612
  }
@@ -29582,6 +29618,7 @@ var init_StateIndicator = __esm({
29582
29618
  init_Box();
29583
29619
  init_Icon();
29584
29620
  init_cn();
29621
+ init_GameIcon();
29585
29622
  DEFAULT_ASSET_URL6 = {
29586
29623
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
29587
29624
  role: "ui",
@@ -29630,14 +29667,15 @@ function TimerDisplay({
29630
29667
  format = "mm:ss",
29631
29668
  size = "md",
29632
29669
  className,
29633
- lowThreshold
29670
+ lowThreshold,
29671
+ iconAsset
29634
29672
  }) {
29635
29673
  const isLow = lowThreshold != null && seconds <= lowThreshold && seconds > 0;
29636
- return /* @__PURE__ */ jsxRuntime.jsx(
29637
- "div",
29674
+ return /* @__PURE__ */ jsxRuntime.jsxs(
29675
+ exports.Box,
29638
29676
  {
29639
29677
  className: cn(
29640
- "inline-flex items-center justify-center rounded-container",
29678
+ "inline-flex items-center gap-1 justify-center rounded-container",
29641
29679
  "bg-card/80 border border-muted font-mono font-bold tabular-nums",
29642
29680
  sizeMap9[size],
29643
29681
  running && "border-success/50",
@@ -29645,7 +29683,10 @@ function TimerDisplay({
29645
29683
  !isLow && "text-foreground",
29646
29684
  className
29647
29685
  ),
29648
- children: formatTime(seconds, format)
29686
+ children: [
29687
+ iconAsset && /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: iconAsset, icon: "image", size: 16, className: "w-4 h-4 object-contain flex-shrink-0" }),
29688
+ formatTime(seconds, format)
29689
+ ]
29649
29690
  }
29650
29691
  );
29651
29692
  }
@@ -29653,6 +29694,8 @@ var sizeMap9;
29653
29694
  var init_TimerDisplay = __esm({
29654
29695
  "components/game/2d/atoms/TimerDisplay.tsx"() {
29655
29696
  init_cn();
29697
+ init_Box();
29698
+ init_GameIcon();
29656
29699
  sizeMap9 = {
29657
29700
  sm: "text-sm px-2 py-0.5",
29658
29701
  md: "text-lg px-3 py-1",
@@ -29673,7 +29716,7 @@ function ResourceCounter({
29673
29716
  }) {
29674
29717
  const sizes = sizeMap10[size];
29675
29718
  return /* @__PURE__ */ jsxRuntime.jsxs(
29676
- "div",
29719
+ exports.Box,
29677
29720
  {
29678
29721
  className: cn(
29679
29722
  "inline-flex items-center rounded-container",
@@ -29682,21 +29725,11 @@ function ResourceCounter({
29682
29725
  className
29683
29726
  ),
29684
29727
  children: [
29685
- assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
29686
- "img",
29687
- {
29688
- src: assetUrl.url,
29689
- alt: label,
29690
- width: sizes.img,
29691
- height: sizes.img,
29692
- style: { imageRendering: "pixelated", objectFit: "contain" },
29693
- className: "flex-shrink-0"
29694
- }
29695
- ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
29696
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
29697
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-bold tabular-nums", color && (color in colorTokenClasses2 ? colorTokenClasses2[color] : color)), children: [
29728
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: sizes.img, alt: label, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
29729
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground", children: label }),
29730
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: cn("font-bold tabular-nums", color && (color in colorTokenClasses2 ? colorTokenClasses2[color] : color)), children: [
29698
29731
  value,
29699
- max != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
29732
+ max != null && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: "text-muted-foreground", children: [
29700
29733
  "/",
29701
29734
  max
29702
29735
  ] })
@@ -29710,6 +29743,9 @@ var init_ResourceCounter = __esm({
29710
29743
  "components/game/2d/atoms/ResourceCounter.tsx"() {
29711
29744
  init_cn();
29712
29745
  init_Icon();
29746
+ init_Box();
29747
+ init_Typography();
29748
+ init_GameIcon();
29713
29749
  colorTokenClasses2 = {
29714
29750
  primary: "text-primary",
29715
29751
  secondary: "text-secondary",
@@ -29741,15 +29777,20 @@ function ItemSlot({
29741
29777
  size = "md",
29742
29778
  selected,
29743
29779
  onClick,
29780
+ action,
29744
29781
  className
29745
29782
  }) {
29746
- const isClickable = onClick != null;
29783
+ const eventBus = useEventBus();
29784
+ const isClickable = onClick != null || action != null;
29747
29785
  const px = assetSizeMap[size];
29748
29786
  return /* @__PURE__ */ jsxRuntime.jsx(
29749
- "button",
29787
+ exports.Button,
29750
29788
  {
29751
- type: "button",
29752
- onClick,
29789
+ variant: "ghost",
29790
+ onClick: () => {
29791
+ if (action) eventBus.emit(`UI:${action}`, {});
29792
+ onClick?.();
29793
+ },
29753
29794
  disabled: !isClickable,
29754
29795
  title: label,
29755
29796
  className: cn(
@@ -29764,21 +29805,12 @@ function ItemSlot({
29764
29805
  !isClickable && "cursor-default",
29765
29806
  className
29766
29807
  ),
29767
- children: empty ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-base", children: "+" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29768
- assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
29769
- "img",
29770
- {
29771
- src: assetUrl?.url,
29772
- alt: label,
29773
- width: px,
29774
- height: px,
29775
- style: { imageRendering: "pixelated", objectFit: "contain" },
29776
- className: "flex-shrink-0"
29777
- }
29778
- ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
29808
+ children: empty ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground text-base", children: "+" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29809
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: px, alt: label, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
29779
29810
  quantity != null && quantity > 1 && /* @__PURE__ */ jsxRuntime.jsx(
29780
- "span",
29811
+ exports.Typography,
29781
29812
  {
29813
+ as: "span",
29782
29814
  className: cn(
29783
29815
  "absolute -bottom-1 -right-1 flex items-center justify-center",
29784
29816
  "min-w-[18px] h-[18px] rounded-full px-1",
@@ -29797,6 +29829,11 @@ var init_ItemSlot = __esm({
29797
29829
  "use client";
29798
29830
  init_cn();
29799
29831
  init_Icon();
29832
+ init_useEventBus();
29833
+ init_Button();
29834
+ init_Box();
29835
+ init_Typography();
29836
+ init_GameIcon();
29800
29837
  sizeMap11 = {
29801
29838
  sm: "w-10 h-10 text-lg",
29802
29839
  md: "w-14 h-14 text-2xl",
@@ -29840,7 +29877,7 @@ function TurnIndicator({
29840
29877
  }) {
29841
29878
  const sizes = sizeMap12[size];
29842
29879
  return /* @__PURE__ */ jsxRuntime.jsxs(
29843
- "div",
29880
+ exports.Box,
29844
29881
  {
29845
29882
  className: cn(
29846
29883
  "inline-flex items-center rounded-container",
@@ -29849,32 +29886,22 @@ function TurnIndicator({
29849
29886
  className
29850
29887
  ),
29851
29888
  children: [
29852
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold tabular-nums", children: [
29889
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: "font-bold tabular-nums", children: [
29853
29890
  "Turn ",
29854
29891
  currentTurn,
29855
- maxTurns != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
29892
+ maxTurns != null && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { as: "span", className: "text-muted-foreground", children: [
29856
29893
  "/",
29857
29894
  maxTurns
29858
29895
  ] })
29859
29896
  ] }),
29860
29897
  phase && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29861
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "|" }),
29862
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: phase })
29898
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground", children: "|" }),
29899
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground", children: phase })
29863
29900
  ] }),
29864
29901
  activeTeam && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29865
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "|" }),
29866
- assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
29867
- "img",
29868
- {
29869
- src: assetUrl.url,
29870
- alt: "",
29871
- width: 12,
29872
- height: 12,
29873
- style: { imageRendering: "pixelated", objectFit: "contain" },
29874
- className: "flex-shrink-0"
29875
- }
29876
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
29877
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-success", children: activeTeam })
29902
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground", children: "|" }),
29903
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: 12, className: "flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: cn("rounded-full bg-success/20", sizes.dot) }),
29904
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-success", children: activeTeam })
29878
29905
  ] })
29879
29906
  ]
29880
29907
  }
@@ -29884,6 +29911,9 @@ var sizeMap12, DEFAULT_ASSET_URL9;
29884
29911
  var init_TurnIndicator = __esm({
29885
29912
  "components/game/2d/atoms/TurnIndicator.tsx"() {
29886
29913
  init_cn();
29914
+ init_Box();
29915
+ init_Typography();
29916
+ init_GameIcon();
29887
29917
  sizeMap12 = {
29888
29918
  sm: { wrapper: "text-xs gap-1.5 px-2 py-0.5", dot: "w-1.5 h-1.5" },
29889
29919
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
@@ -29907,53 +29937,47 @@ function WaypointMarker({
29907
29937
  className
29908
29938
  }) {
29909
29939
  const sizes = sizeMap13[size];
29910
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col items-center", className), children: [
29911
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
29940
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn("flex flex-col items-center", className), children: [
29941
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "relative flex items-center justify-center", children: [
29912
29942
  active && /* @__PURE__ */ jsxRuntime.jsx(
29913
- "div",
29943
+ exports.Box,
29914
29944
  {
29945
+ position: "absolute",
29915
29946
  className: cn(
29916
- "absolute rounded-full border-2 border-info animate-ping opacity-50",
29947
+ "rounded-full border-2 border-info animate-ping opacity-50",
29917
29948
  sizes.ring
29918
29949
  )
29919
29950
  }
29920
29951
  ),
29921
29952
  active && /* @__PURE__ */ jsxRuntime.jsx(
29922
- "div",
29953
+ exports.Box,
29923
29954
  {
29955
+ position: "absolute",
29924
29956
  className: cn(
29925
- "absolute rounded-full border-2 border-info",
29957
+ "rounded-full border-2 border-info",
29926
29958
  sizes.ring
29927
29959
  )
29928
29960
  }
29929
29961
  ),
29930
29962
  /* @__PURE__ */ jsxRuntime.jsx(
29931
- "div",
29963
+ exports.Box,
29932
29964
  {
29965
+ position: "relative",
29933
29966
  className: cn(
29934
- "relative flex items-center justify-center rounded-full transition-all duration-200",
29967
+ "flex items-center justify-center rounded-full transition-all duration-200",
29935
29968
  sizes.dot,
29936
29969
  completed && "bg-success text-foreground",
29937
29970
  active && !completed && "bg-info text-foreground",
29938
29971
  !active && !completed && "bg-muted"
29939
29972
  ),
29940
- children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
29941
- "img",
29942
- {
29943
- src: assetUrl.url,
29944
- alt: label,
29945
- width: sizes.img,
29946
- height: sizes.img,
29947
- style: { imageRendering: "pixelated", objectFit: "contain" },
29948
- className: "flex-shrink-0"
29949
- }
29950
- ) : icon ? typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) : null
29973
+ children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: sizes.img, alt: label, className: "flex-shrink-0" }) : icon ? typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) : null
29951
29974
  }
29952
29975
  )
29953
29976
  ] }),
29954
29977
  label && /* @__PURE__ */ jsxRuntime.jsx(
29955
- "span",
29978
+ exports.Typography,
29956
29979
  {
29980
+ as: "span",
29957
29981
  className: cn(
29958
29982
  "text-center whitespace-nowrap",
29959
29983
  sizes.label,
@@ -29969,6 +29993,9 @@ var init_WaypointMarker = __esm({
29969
29993
  "components/game/2d/atoms/WaypointMarker.tsx"() {
29970
29994
  init_cn();
29971
29995
  init_Icon();
29996
+ init_Box();
29997
+ init_Typography();
29998
+ init_GameIcon();
29972
29999
  DEFAULT_ASSET_URL10 = {
29973
30000
  url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
29974
30001
  role: "ui",
@@ -30000,31 +30027,23 @@ function StatusEffect({
30000
30027
  className
30001
30028
  }) {
30002
30029
  const sizes = sizeMap14[size];
30003
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative inline-flex flex-col items-center", className), children: [
30030
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { position: "relative", className: cn("inline-flex flex-col items-center", className), children: [
30004
30031
  /* @__PURE__ */ jsxRuntime.jsxs(
30005
- "div",
30032
+ exports.Box,
30006
30033
  {
30034
+ position: "relative",
30007
30035
  className: cn(
30008
- "relative flex items-center justify-center rounded-interactive border-2",
30036
+ "flex items-center justify-center rounded-interactive border-2",
30009
30037
  sizes.container,
30010
30038
  variantStyles8[variant]
30011
30039
  ),
30012
30040
  title: label,
30013
30041
  children: [
30014
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
30015
- "img",
30016
- {
30017
- src: assetUrl.url,
30018
- alt: label,
30019
- width: sizes.img,
30020
- height: sizes.img,
30021
- style: { imageRendering: "pixelated", objectFit: "contain" },
30022
- className: "flex-shrink-0"
30023
- }
30024
- ) : icon != null && typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, size: "sm" }) : icon != null ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, size: "sm" }) : null }),
30042
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl, icon: "image", size: sizes.img, alt: label, className: "flex-shrink-0" }) : icon != null && typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, size: "sm" }) : icon != null ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, size: "sm" }) : null }),
30025
30043
  duration !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
30026
- "span",
30044
+ exports.Typography,
30027
30045
  {
30046
+ as: "span",
30028
30047
  className: cn(
30029
30048
  "absolute bottom-0 left-0 right-0 text-center font-mono font-bold text-foreground bg-background/60 leading-tight",
30030
30049
  sizes.timer
@@ -30036,8 +30055,9 @@ function StatusEffect({
30036
30055
  }
30037
30056
  ),
30038
30057
  stacks !== void 0 && stacks > 1 && /* @__PURE__ */ jsxRuntime.jsx(
30039
- "span",
30058
+ exports.Typography,
30040
30059
  {
30060
+ as: "span",
30041
30061
  className: cn(
30042
30062
  "absolute flex items-center justify-center rounded-full bg-card text-foreground font-bold leading-none",
30043
30063
  sizes.badge
@@ -30045,7 +30065,7 @@ function StatusEffect({
30045
30065
  children: stacks
30046
30066
  }
30047
30067
  ),
30048
- label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
30068
+ label && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
30049
30069
  ] });
30050
30070
  }
30051
30071
  var DEFAULT_ASSET_URL11, sizeMap14, variantStyles8;
@@ -30053,6 +30073,9 @@ var init_StatusEffect = __esm({
30053
30073
  "components/game/2d/atoms/StatusEffect.tsx"() {
30054
30074
  init_cn();
30055
30075
  init_Icon();
30076
+ init_Box();
30077
+ init_Typography();
30078
+ init_GameIcon();
30056
30079
  DEFAULT_ASSET_URL11 = {
30057
30080
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
30058
30081
  role: "ui",
@@ -30079,7 +30102,7 @@ function DialogueBubble({
30079
30102
  className
30080
30103
  }) {
30081
30104
  return /* @__PURE__ */ jsxRuntime.jsxs(
30082
- "div",
30105
+ exports.Box,
30083
30106
  {
30084
30107
  className: cn(
30085
30108
  "flex items-start gap-3 rounded-container bg-background/80 backdrop-blur-sm px-4 py-3 border border-border/10",
@@ -30087,17 +30110,10 @@ function DialogueBubble({
30087
30110
  className
30088
30111
  ),
30089
30112
  children: [
30090
- portrait && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsxRuntime.jsx(
30091
- "img",
30092
- {
30093
- src: portrait?.url,
30094
- alt: speaker ?? "speaker",
30095
- className: "w-full h-full object-cover"
30096
- }
30097
- ) }),
30098
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 min-w-0", children: [
30099
- speaker && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold text-warning", children: speaker }),
30100
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground leading-relaxed", children: text })
30113
+ portrait && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: portrait, icon: "image", size: 48, alt: speaker ?? "speaker", className: "w-full h-full object-cover" }) }),
30114
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex flex-col gap-1 min-w-0", children: [
30115
+ speaker && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-sm font-bold text-warning", children: speaker }),
30116
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-sm text-foreground leading-relaxed", children: text })
30101
30117
  ] })
30102
30118
  ]
30103
30119
  }
@@ -30107,6 +30123,9 @@ var DEFAULT_PORTRAIT;
30107
30123
  var init_DialogueBubble = __esm({
30108
30124
  "components/game/2d/atoms/DialogueBubble.tsx"() {
30109
30125
  init_cn();
30126
+ init_Box();
30127
+ init_Typography();
30128
+ init_GameIcon();
30110
30129
  DEFAULT_PORTRAIT = {
30111
30130
  url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
30112
30131
  role: "effect",
@@ -30133,7 +30152,7 @@ function StatBadge({
30133
30152
  const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
30134
30153
  const resolvedAsset = iconUrl ?? assetUrl;
30135
30154
  return /* @__PURE__ */ jsxRuntime.jsxs(
30136
- "div",
30155
+ exports.Box,
30137
30156
  {
30138
30157
  className: cn(
30139
30158
  "inline-flex items-center gap-2 rounded-container border backdrop-blur-sm",
@@ -30142,18 +30161,8 @@ function StatBadge({
30142
30161
  className
30143
30162
  ),
30144
30163
  children: [
30145
- resolvedAsset ? /* @__PURE__ */ jsxRuntime.jsx(
30146
- "img",
30147
- {
30148
- src: resolvedAsset.url,
30149
- alt: "",
30150
- width: 16,
30151
- height: 16,
30152
- style: { imageRendering: "pixelated", objectFit: "contain" },
30153
- className: "flex-shrink-0"
30154
- }
30155
- ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, className: "w-4 h-4" }) }) : null,
30156
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground font-medium", children: label }),
30164
+ resolvedAsset ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: resolvedAsset, icon: "image", size: 16, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, className: "w-4 h-4" }) }) : null,
30165
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground font-medium", children: label }),
30157
30166
  format === "hearts" && max && /* @__PURE__ */ jsxRuntime.jsx(
30158
30167
  HealthBar,
30159
30168
  {
@@ -30179,7 +30188,7 @@ function StatBadge({
30179
30188
  size: size === "lg" ? "md" : "sm"
30180
30189
  }
30181
30190
  ),
30182
- format === "text" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold text-foreground", children: value })
30191
+ format === "text" && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "font-bold text-foreground", children: value })
30183
30192
  ]
30184
30193
  }
30185
30194
  );
@@ -30189,6 +30198,9 @@ var init_StatBadge = __esm({
30189
30198
  "components/game/2d/molecules/StatBadge.tsx"() {
30190
30199
  init_cn();
30191
30200
  init_Icon();
30201
+ init_Box();
30202
+ init_Typography();
30203
+ init_GameIcon();
30192
30204
  init_HealthBar();
30193
30205
  init_ScoreDisplay();
30194
30206
  sizeMap15 = {
@@ -30223,7 +30235,7 @@ function InventoryGrid({
30223
30235
  (id) => {
30224
30236
  onSelect?.(id);
30225
30237
  if (selectEvent) {
30226
- eventBus.emit(selectEvent, { id });
30238
+ eventBus.emit(`UI:${selectEvent}`, { id });
30227
30239
  }
30228
30240
  },
30229
30241
  [onSelect, selectEvent, eventBus]
@@ -30366,9 +30378,9 @@ function GameHud({
30366
30378
  if (position === "corners") {
30367
30379
  const leftStats = stats.slice(0, Math.ceil(stats.length / 2));
30368
30380
  const rightStats = stats.slice(Math.ceil(stats.length / 2));
30369
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", positionMap[position], className), children: [
30370
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-4 left-4 flex flex-col gap-2 pointer-events-auto", children: leftStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) }),
30371
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-4 right-4 flex flex-col gap-2 items-end pointer-events-auto", children: rightStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) })
30381
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { position: "relative", className: cn(positionMap[position], className), children: [
30382
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { position: "absolute", className: "top-4 left-4 flex flex-col gap-2 pointer-events-auto", children: leftStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) }),
30383
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { position: "absolute", className: "top-4 right-4 flex flex-col gap-2 items-end pointer-events-auto", children: rightStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) })
30372
30384
  ] });
30373
30385
  }
30374
30386
  if (position === "top" || position === "bottom") {
@@ -30377,7 +30389,7 @@ function GameHud({
30377
30389
  const rightStats = stats.slice(mid);
30378
30390
  const isTop = position === "top";
30379
30391
  return /* @__PURE__ */ jsxRuntime.jsxs(
30380
- "div",
30392
+ exports.Box,
30381
30393
  {
30382
30394
  className: cn(
30383
30395
  "flex items-center justify-between w-full",
@@ -30387,17 +30399,18 @@ function GameHud({
30387
30399
  className
30388
30400
  ),
30389
30401
  children: [
30390
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 flex-shrink-0", children: leftStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) }),
30391
- rightStats.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 flex-shrink-0", children: rightStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) })
30402
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex items-center gap-3 flex-shrink-0", children: leftStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) }),
30403
+ rightStats.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex items-center gap-3 flex-shrink-0", children: rightStats.map((stat, i) => /* @__PURE__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) })
30392
30404
  ]
30393
30405
  }
30394
30406
  );
30395
30407
  }
30396
30408
  return /* @__PURE__ */ jsxRuntime.jsx(
30397
- "div",
30409
+ exports.Box,
30398
30410
  {
30411
+ position: "relative",
30399
30412
  className: cn(
30400
- "relative z-10 flex items-center gap-4 px-4 py-2",
30413
+ "z-10 flex items-center gap-4 px-4 py-2",
30401
30414
  transparent ? "bg-black/30 backdrop-blur-sm" : "bg-surface/90 backdrop-blur-sm",
30402
30415
  className
30403
30416
  ),
@@ -30409,6 +30422,7 @@ var positionMap, DEFAULT_HUD_STATS;
30409
30422
  var init_GameHud = __esm({
30410
30423
  "components/game/2d/molecules/GameHud.tsx"() {
30411
30424
  init_cn();
30425
+ init_Box();
30412
30426
  init_StatBadge();
30413
30427
  positionMap = {
30414
30428
  corners: "inset-0 pointer-events-none"
@@ -30428,34 +30442,28 @@ function GameMenu({
30428
30442
  options,
30429
30443
  menuItems,
30430
30444
  onSelect,
30431
- eventBus: eventBusProp,
30432
30445
  background,
30433
- logo = "",
30446
+ logo,
30434
30447
  className
30435
30448
  }) {
30436
30449
  const resolvedOptions = options ?? menuItems ?? DEFAULT_MENU_OPTIONS;
30437
- let eventBusFromHook = null;
30438
- try {
30439
- eventBusFromHook = useEventBus();
30440
- } catch {
30441
- }
30442
- const eventBus = eventBusProp || eventBusFromHook;
30450
+ const eventBus = useEventBus();
30443
30451
  const handleOptionClick = React79__namespace.useCallback(
30444
30452
  (option) => {
30445
- if (option.event && eventBus) {
30453
+ if (option.event) {
30446
30454
  eventBus.emit(`UI:${option.event}`, { option });
30447
30455
  }
30448
30456
  if (onSelect) {
30449
30457
  onSelect(option);
30450
30458
  }
30451
- if (option.navigatesTo && eventBus) {
30459
+ if (option.navigatesTo) {
30452
30460
  eventBus.emit("UI:NAVIGATE", { url: option.navigatesTo, option });
30453
30461
  }
30454
30462
  },
30455
30463
  [eventBus, onSelect]
30456
30464
  );
30457
30465
  return /* @__PURE__ */ jsxRuntime.jsxs(
30458
- "div",
30466
+ exports.Box,
30459
30467
  {
30460
30468
  className: cn(
30461
30469
  "min-h-screen w-full flex flex-col items-center justify-center p-8",
@@ -30465,18 +30473,12 @@ function GameMenu({
30465
30473
  background: background ?? "linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f0e17 100%)"
30466
30474
  },
30467
30475
  children: [
30468
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-12 animate-fade-in", children: [
30469
- logo && /* @__PURE__ */ jsxRuntime.jsx(
30470
- "img",
30471
- {
30472
- src: logo,
30473
- alt: title,
30474
- className: "h-24 w-auto mx-auto mb-6 drop-shadow-2xl"
30475
- }
30476
- ),
30476
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "text-center mb-12 animate-fade-in", children: [
30477
+ logo && /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: logo, icon: "image", size: 96, alt: title, className: "h-24 w-auto mx-auto mb-6 drop-shadow-2xl" }),
30477
30478
  /* @__PURE__ */ jsxRuntime.jsx(
30478
- "h1",
30479
+ exports.Typography,
30479
30480
  {
30481
+ variant: "h1",
30480
30482
  className: "text-5xl md:text-7xl font-bold text-[var(--color-foreground)] tracking-tight",
30481
30483
  style: {
30482
30484
  textShadow: "0 4px 12px rgba(0,0,0,0.5)"
@@ -30484,9 +30486,9 @@ function GameMenu({
30484
30486
  children: title
30485
30487
  }
30486
30488
  ),
30487
- subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-lg text-muted-foreground tracking-widest uppercase", children: subtitle })
30489
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className: "mt-2 text-lg text-muted-foreground tracking-widest uppercase", children: subtitle })
30488
30490
  ] }),
30489
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4 w-full max-w-md", children: resolvedOptions.map((option, index) => /* @__PURE__ */ jsxRuntime.jsx(
30491
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex flex-col gap-4 w-full max-w-md", children: resolvedOptions.map((option, index) => /* @__PURE__ */ jsxRuntime.jsx(
30490
30492
  ChoiceButton,
30491
30493
  {
30492
30494
  text: option.label,
@@ -30497,9 +30499,9 @@ function GameMenu({
30497
30499
  },
30498
30500
  index
30499
30501
  )) }),
30500
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none overflow-hidden", children: [
30501
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1/4 left-1/4 w-64 h-64 bg-info/10 rounded-container blur-3xl" }),
30502
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-1/4 right-1/4 w-96 h-96 bg-accent/10 rounded-container blur-3xl" })
30502
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { position: "absolute", className: "inset-0 pointer-events-none overflow-hidden", children: [
30503
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { position: "absolute", className: "top-1/4 left-1/4 w-64 h-64 bg-info/10 rounded-container blur-3xl" }),
30504
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { position: "absolute", className: "bottom-1/4 right-1/4 w-96 h-96 bg-accent/10 rounded-container blur-3xl" })
30503
30505
  ] })
30504
30506
  ]
30505
30507
  }
@@ -30511,6 +30513,9 @@ var init_GameMenu = __esm({
30511
30513
  "use client";
30512
30514
  init_cn();
30513
30515
  init_useEventBus();
30516
+ init_Box();
30517
+ init_Typography();
30518
+ init_GameIcon();
30514
30519
  init_ChoiceButton();
30515
30520
  DEFAULT_MENU_OPTIONS = [
30516
30521
  { label: "New Game", event: "NEW_GAME", variant: "primary" },
@@ -30929,7 +30934,9 @@ var init_GameAudioProvider = __esm({
30929
30934
  });
30930
30935
  function GameAudioToggle({
30931
30936
  size = "sm",
30932
- className
30937
+ className,
30938
+ onAsset,
30939
+ offAsset
30933
30940
  }) {
30934
30941
  const ctx = useGameAudioContextOptional();
30935
30942
  const [localMuted, setLocalMuted] = React79.useState(false);
@@ -30938,6 +30945,7 @@ function GameAudioToggle({
30938
30945
  const handleToggle = React79.useCallback(() => {
30939
30946
  setMuted(!muted);
30940
30947
  }, [muted, setMuted]);
30948
+ const activeAsset = muted ? offAsset : onAsset;
30941
30949
  return /* @__PURE__ */ jsxRuntime.jsx(
30942
30950
  exports.Button,
30943
30951
  {
@@ -30946,7 +30954,7 @@ function GameAudioToggle({
30946
30954
  onClick: handleToggle,
30947
30955
  className: cn("text-lg leading-none px-2", className),
30948
30956
  "aria-pressed": muted,
30949
- children: muted ? "\u{1F507}" : "\u{1F50A}"
30957
+ children: activeAsset ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: activeAsset, icon: "image", size: 20, alt: muted ? "Muted" : "Sound on", className: "w-5 h-5 object-contain" }) : muted ? "\u{1F507}" : "\u{1F50A}"
30950
30958
  }
30951
30959
  );
30952
30960
  }
@@ -30956,6 +30964,7 @@ var init_GameAudioToggle = __esm({
30956
30964
  init_atoms();
30957
30965
  init_cn();
30958
30966
  init_GameAudioProvider();
30967
+ init_GameIcon();
30959
30968
  GameAudioToggle.displayName = "GameAudioToggle";
30960
30969
  }
30961
30970
  });
@@ -31535,6 +31544,7 @@ function PlatformerBoard({
31535
31544
  canvasHeight: _canvasHeight = 400,
31536
31545
  playerSprite,
31537
31546
  tileSprites,
31547
+ ui: _ui,
31538
31548
  bgColor: _bgColor,
31539
31549
  keyEvent = "KEY",
31540
31550
  playAgainEvent = "PLAY_AGAIN",
@@ -32959,6 +32969,7 @@ function TanksBoard({
32959
32969
  features,
32960
32970
  assetManifest,
32961
32971
  assetBaseUrl,
32972
+ ui: _ui,
32962
32973
  scale = 0.45,
32963
32974
  showMinimap = true,
32964
32975
  enableCamera = true,
@@ -33666,7 +33677,7 @@ function TraitSlot({
33666
33677
  size = "md",
33667
33678
  showTooltip = true,
33668
33679
  categoryColors,
33669
- tooltipFrameUrl = "",
33680
+ tooltipFrameUrl,
33670
33681
  className,
33671
33682
  feedback,
33672
33683
  onItemDrop,
@@ -33796,7 +33807,7 @@ function TraitSlot({
33796
33807
  as: "img",
33797
33808
  className: "object-contain",
33798
33809
  style: { width: config.icon, height: config.icon },
33799
- ...{ src: equippedItem.iconUrl, alt: equippedItem.name }
33810
+ ...{ src: equippedItem.iconUrl.url, alt: equippedItem.name }
33800
33811
  }
33801
33812
  ) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "text-center leading-none", style: { fontSize: config.icon }, children: equippedItem.iconEmoji || "\u2726" }),
33802
33813
  (onRemove || removeEvent) && /* @__PURE__ */ jsxRuntime.jsx(
@@ -33825,7 +33836,7 @@ function TraitSlot({
33825
33836
  ...getTooltipStyle(),
33826
33837
  minWidth: 200,
33827
33838
  ...tooltipFrameUrl ? {
33828
- borderImage: `url(${tooltipFrameUrl}) 60 fill / 15px / 0 stretch`,
33839
+ borderImage: `url(${tooltipFrameUrl.url}) 60 fill / 15px / 0 stretch`,
33829
33840
  border: "none"
33830
33841
  } : {}
33831
33842
  },
@@ -34122,6 +34133,42 @@ function computeSlotFeedback(playerSeq, solutions) {
34122
34133
  (id, i) => id !== void 0 && id === bestSolution[i] ? "correct" : "wrong"
34123
34134
  );
34124
34135
  }
34136
+ function isFieldRecord(v) {
34137
+ return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Date);
34138
+ }
34139
+ function assetFromField(v) {
34140
+ if (!isFieldRecord(v)) return void 0;
34141
+ const url = typeof v.url === "string" ? v.url : void 0;
34142
+ const role = typeof v.role === "string" ? v.role : void 0;
34143
+ const category = typeof v.category === "string" ? v.category : "";
34144
+ if (!url || !role) return void 0;
34145
+ return {
34146
+ url,
34147
+ role,
34148
+ category,
34149
+ name: typeof v.name === "string" ? v.name : void 0,
34150
+ thumbnailUrl: typeof v.thumbnailUrl === "string" ? v.thumbnailUrl : void 0,
34151
+ style: typeof v.style === "string" ? v.style : void 0,
34152
+ variant: typeof v.variant === "string" ? v.variant : void 0,
34153
+ dimension: typeof v.dimension === "string" ? v.dimension : void 0,
34154
+ aspect: typeof v.aspect === "string" ? v.aspect : void 0
34155
+ };
34156
+ }
34157
+ function slotItemFromField(fv) {
34158
+ if (!isFieldRecord(fv)) return void 0;
34159
+ const id = typeof fv.id === "string" ? fv.id : void 0;
34160
+ const name = typeof fv.name === "string" ? fv.name : void 0;
34161
+ const category = typeof fv.category === "string" ? fv.category : void 0;
34162
+ if (!id || !name || !category) return void 0;
34163
+ return {
34164
+ id,
34165
+ name,
34166
+ category,
34167
+ description: typeof fv.description === "string" ? fv.description : void 0,
34168
+ iconEmoji: typeof fv.iconEmoji === "string" ? fv.iconEmoji : void 0,
34169
+ iconUrl: assetFromField(fv.iconUrl)
34170
+ };
34171
+ }
34125
34172
  function SequencerBoard({
34126
34173
  entity,
34127
34174
  categoryColors,
@@ -34132,6 +34179,7 @@ function SequencerBoard({
34132
34179
  removeEvent,
34133
34180
  checkEvent,
34134
34181
  playAgainEvent,
34182
+ stepEvent,
34135
34183
  className
34136
34184
  }) {
34137
34185
  const { emit } = useEventBus();
@@ -34139,7 +34187,11 @@ function SequencerBoard({
34139
34187
  const resolved = boardEntity(entity);
34140
34188
  const maxSlots = num(resolved?.maxSlots) || 3;
34141
34189
  const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
34142
- const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
34190
+ const availableActions = (Array.isArray(resolved?.availableActions) ? resolved.availableActions : []).reduce((acc, fv) => {
34191
+ const item = slotItemFromField(fv);
34192
+ if (item) acc.push(item);
34193
+ return acc;
34194
+ }, []);
34143
34195
  const allowDuplicates = resolved?.allowDuplicates !== false;
34144
34196
  const entitySlots = Array.isArray(resolved?.slots) ? resolved.slots : [];
34145
34197
  const entityResult = str(resolved?.result);
@@ -34197,7 +34249,7 @@ function SequencerBoard({
34197
34249
  let step = 0;
34198
34250
  const advance = () => {
34199
34251
  step++;
34200
- emit("UI:STEP", { step });
34252
+ if (stepEvent) emit(`UI:${stepEvent}`, { step });
34201
34253
  if (step >= maxSlots) {
34202
34254
  if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
34203
34255
  const playerSeq = slots.map((s) => s?.id);
@@ -36096,24 +36148,55 @@ function SimulationControls({
36096
36148
  onReset,
36097
36149
  onSpeedChange,
36098
36150
  onParameterChange,
36151
+ playEvent,
36152
+ pauseEvent,
36153
+ stepEvent,
36154
+ resetEvent,
36155
+ speedChangeEvent,
36156
+ parameterChangeEvent,
36099
36157
  assetManifest,
36100
36158
  className
36101
36159
  }) {
36160
+ const eventBus = useEventBus();
36102
36161
  const ui = assetManifest?.ui;
36162
+ const handlePlay = () => {
36163
+ if (playEvent) eventBus.emit(`UI:${playEvent}`, {});
36164
+ onPlay?.();
36165
+ };
36166
+ const handlePause = () => {
36167
+ if (pauseEvent) eventBus.emit(`UI:${pauseEvent}`, {});
36168
+ onPause?.();
36169
+ };
36170
+ const handleStep = () => {
36171
+ if (stepEvent) eventBus.emit(`UI:${stepEvent}`, {});
36172
+ onStep?.();
36173
+ };
36174
+ const handleReset = () => {
36175
+ if (resetEvent) eventBus.emit(`UI:${resetEvent}`, {});
36176
+ onReset?.();
36177
+ };
36178
+ const handleSpeedChange = (s) => {
36179
+ if (speedChangeEvent) eventBus.emit(`UI:${speedChangeEvent}`, { speed: s });
36180
+ onSpeedChange?.(s);
36181
+ };
36182
+ const handleParameterChange = (name, value) => {
36183
+ if (parameterChangeEvent) eventBus.emit(`UI:${parameterChangeEvent}`, { name, value });
36184
+ onParameterChange?.(name, value);
36185
+ };
36103
36186
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "md", className, children: [
36104
36187
  /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", align: "center", children: [
36105
- running ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "secondary", onClick: onPause, children: [
36188
+ running ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "secondary", onClick: handlePause, children: [
36106
36189
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.Pause, assetUrl: ui?.["pause"], size: "sm" }),
36107
36190
  "Pause"
36108
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "primary", onClick: onPlay, children: [
36191
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "primary", onClick: handlePlay, children: [
36109
36192
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.Play, assetUrl: ui?.["play"], size: "sm" }),
36110
36193
  "Play"
36111
36194
  ] }),
36112
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: onStep, disabled: running, children: [
36195
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: handleStep, disabled: running, children: [
36113
36196
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.SkipForward, assetUrl: ui?.["step"], size: "sm" }),
36114
36197
  "Step"
36115
36198
  ] }),
36116
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: onReset, children: [
36199
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: handleReset, children: [
36117
36200
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.RotateCcw, assetUrl: ui?.["reset"], size: "sm" }),
36118
36201
  "Reset"
36119
36202
  ] })
@@ -36132,7 +36215,7 @@ function SimulationControls({
36132
36215
  max: 5,
36133
36216
  step: 0.1,
36134
36217
  value: speed,
36135
- onChange: (e) => onSpeedChange(parseFloat(e.target.value)),
36218
+ onChange: (e) => handleSpeedChange(parseFloat(e.target.value)),
36136
36219
  className: "w-full"
36137
36220
  }
36138
36221
  )
@@ -36151,7 +36234,7 @@ function SimulationControls({
36151
36234
  max: param.max,
36152
36235
  step: param.step,
36153
36236
  value: param.value,
36154
- onChange: (e) => onParameterChange(name, parseFloat(e.target.value)),
36237
+ onChange: (e) => handleParameterChange(name, parseFloat(e.target.value)),
36155
36238
  className: "w-full"
36156
36239
  }
36157
36240
  )
@@ -36160,6 +36243,7 @@ function SimulationControls({
36160
36243
  }
36161
36244
  var init_SimulationControls = __esm({
36162
36245
  "components/game/2d/organisms/SimulationControls.tsx"() {
36246
+ init_useEventBus();
36163
36247
  init_atoms();
36164
36248
  init_GameIcon();
36165
36249
  SimulationControls.displayName = "SimulationControls";
@@ -36228,35 +36312,7 @@ var init_SimulationGraph = __esm({
36228
36312
  SimulationGraph.displayName = "SimulationGraph";
36229
36313
  }
36230
36314
  });
36231
- function getSlotContentRenderer() {
36232
- if (_scr) return _scr;
36233
- const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
36234
- _scr = mod.SlotContentRenderer;
36235
- return _scr;
36236
- }
36237
- function resolveDescriptor(value, idPrefix) {
36238
- if (value === null || value === void 0) return value;
36239
- if (React79__namespace.default.isValidElement(value)) return value;
36240
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
36241
- if (Array.isArray(value)) {
36242
- return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React79__namespace.default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
36243
- }
36244
- if (typeof value === "object") {
36245
- const rec = value;
36246
- if (typeof rec.type === "string" && patterns.getComponentForPattern(rec.type) !== null) {
36247
- const type = rec.type;
36248
- const _id = typeof rec._id === "string" ? rec._id : void 0;
36249
- const nestedProps = rec.props !== void 0 && typeof rec.props === "object" && !Array.isArray(rec.props) && rec.props !== null ? rec.props : void 0;
36250
- const { type: _t, props: _p, _id: _d, ...flatRest } = rec;
36251
- const resolvedProps = nestedProps !== void 0 ? nestedProps : flatRest;
36252
- const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
36253
- const SCR = getSlotContentRenderer();
36254
- return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
36255
- }
36256
- }
36257
- return null;
36258
- }
36259
- var _scr; exports.GameTemplate = void 0;
36315
+ exports.GameTemplate = void 0;
36260
36316
  var init_GameTemplate = __esm({
36261
36317
  "components/game/2d/templates/GameTemplate.tsx"() {
36262
36318
  init_cn();
@@ -36264,7 +36320,6 @@ var init_GameTemplate = __esm({
36264
36320
  init_Stack();
36265
36321
  init_Typography();
36266
36322
  init_Button();
36267
- _scr = null;
36268
36323
  exports.GameTemplate = ({
36269
36324
  entity,
36270
36325
  title = "Game",
@@ -36273,7 +36328,8 @@ var init_GameTemplate = __esm({
36273
36328
  debugPanel,
36274
36329
  showDebugPanel = false,
36275
36330
  controls,
36276
- className
36331
+ className,
36332
+ backgroundAsset
36277
36333
  }) => {
36278
36334
  return /* @__PURE__ */ jsxRuntime.jsxs(
36279
36335
  exports.Box,
@@ -36330,15 +36386,16 @@ var init_GameTemplate = __esm({
36330
36386
  {
36331
36387
  position: "relative",
36332
36388
  fullWidth: true,
36333
- className: "flex-1 bg-muted",
36389
+ className: backgroundAsset ? "flex-1" : "flex-1 bg-muted",
36390
+ style: backgroundAsset ? { backgroundImage: `url(${backgroundAsset.url})`, backgroundSize: "cover", backgroundPosition: "center" } : void 0,
36334
36391
  children: [
36335
- resolveDescriptor(children, "gt-children"),
36392
+ children,
36336
36393
  hud && /* @__PURE__ */ jsxRuntime.jsx(
36337
36394
  exports.Box,
36338
36395
  {
36339
36396
  position: "absolute",
36340
36397
  className: "top-0 left-0 right-0 pointer-events-none",
36341
- children: /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", className: "pointer-events-auto w-fit", children: resolveDescriptor(hud, "gt-hud") })
36398
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
36342
36399
  }
36343
36400
  )
36344
36401
  ]
@@ -36363,7 +36420,7 @@ var init_GameTemplate = __esm({
36363
36420
  children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h6", children: "Debug Panel" })
36364
36421
  }
36365
36422
  ),
36366
- /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", children: resolveDescriptor(debugPanel, "gt-debug") })
36423
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", children: debugPanel })
36367
36424
  ]
36368
36425
  }
36369
36426
  )
@@ -36374,59 +36431,21 @@ var init_GameTemplate = __esm({
36374
36431
  exports.GameTemplate.displayName = "GameTemplate";
36375
36432
  }
36376
36433
  });
36377
- function asDescriptor(v) {
36378
- if (Array.isArray(v) || React79__namespace.default.isValidElement(v)) return null;
36379
- const o = v;
36380
- if (typeof o.type !== "string") return null;
36381
- const props = o.props !== void 0 && typeof o.props === "object" && !Array.isArray(o.props) && o.props !== null ? o.props : void 0;
36382
- const _id = typeof o._id === "string" ? o._id : void 0;
36383
- const sourceTrait = typeof o.sourceTrait === "string" ? o.sourceTrait : void 0;
36384
- return { type: o.type, props, _id, sourceTrait };
36385
- }
36386
- function getSlotContentRenderer2() {
36387
- if (_scr2) return _scr2;
36388
- const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
36389
- _scr2 = mod.SlotContentRenderer;
36390
- return _scr2;
36391
- }
36392
- function resolveDescriptor2(value, idPrefix) {
36393
- if (value === null || value === void 0) return value;
36394
- if (React79__namespace.default.isValidElement(value)) return value;
36395
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
36396
- if (Array.isArray(value)) {
36397
- return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React79__namespace.default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
36398
- }
36399
- if (typeof value === "object" && value !== null) {
36400
- const desc = asDescriptor(value);
36401
- if (desc !== null && patterns.getComponentForPattern(desc.type) !== null) {
36402
- const resolvedProps = desc.props ?? {};
36403
- const content = {
36404
- id: desc._id ?? idPrefix,
36405
- pattern: desc.type,
36406
- props: resolvedProps,
36407
- priority: 0,
36408
- ...desc.sourceTrait !== void 0 && { sourceTrait: desc.sourceTrait }
36409
- };
36410
- const SCR = getSlotContentRenderer2();
36411
- return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
36412
- }
36413
- }
36414
- return null;
36415
- }
36416
- var _scr2; exports.GameShell = void 0;
36434
+ exports.GameShell = void 0;
36417
36435
  var init_GameShell = __esm({
36418
36436
  "components/game/2d/templates/GameShell.tsx"() {
36419
36437
  init_cn();
36420
36438
  init_Box();
36421
36439
  init_Stack();
36422
36440
  init_Typography();
36423
- _scr2 = null;
36424
36441
  exports.GameShell = ({
36425
36442
  appName = "Game",
36426
36443
  hud,
36427
36444
  className,
36428
36445
  showTopBar = true,
36429
- children
36446
+ children,
36447
+ backgroundAsset,
36448
+ hudBackgroundAsset
36430
36449
  }) => {
36431
36450
  return /* @__PURE__ */ jsxRuntime.jsxs(
36432
36451
  exports.Box,
@@ -36441,7 +36460,7 @@ var init_GameShell = __esm({
36441
36460
  width: "100vw",
36442
36461
  height: "100vh",
36443
36462
  overflow: "hidden",
36444
- background: "var(--color-background, #0a0a0f)",
36463
+ background: backgroundAsset ? `url(${backgroundAsset.url}) center/cover no-repeat` : "var(--color-background, #0a0a0f)",
36445
36464
  color: "var(--color-text, #e0e0e0)"
36446
36465
  },
36447
36466
  children: [
@@ -36451,7 +36470,7 @@ var init_GameShell = __esm({
36451
36470
  className: "game-shell__header",
36452
36471
  style: {
36453
36472
  flexShrink: 0,
36454
- background: "var(--color-surface, #12121f)",
36473
+ background: hudBackgroundAsset ? `url(${hudBackgroundAsset.url}) center/cover no-repeat` : "var(--color-surface, #12121f)",
36455
36474
  borderBottom: "1px solid var(--color-border, #2a2a3a)"
36456
36475
  },
36457
36476
  children: [
@@ -36474,7 +36493,7 @@ var init_GameShell = __esm({
36474
36493
  )
36475
36494
  }
36476
36495
  ),
36477
- hud && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "game-shell__hud", style: { width: "100%" }, children: resolveDescriptor2(hud, "gs-hud") })
36496
+ hud && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "game-shell__hud", style: { width: "100%" }, children: hud })
36478
36497
  ]
36479
36498
  }
36480
36499
  ),
@@ -36487,7 +36506,7 @@ var init_GameShell = __esm({
36487
36506
  overflow: "hidden",
36488
36507
  position: "relative"
36489
36508
  },
36490
- children: resolveDescriptor2(children, "gs-children")
36509
+ children
36491
36510
  }
36492
36511
  )
36493
36512
  ]
@@ -45161,6 +45180,7 @@ var init_WizardContainer = __esm({
45161
45180
  init_Stack();
45162
45181
  init_Icon();
45163
45182
  init_cn();
45183
+ init_useEventBus();
45164
45184
  exports.WizardContainer = ({
45165
45185
  steps,
45166
45186
  currentStep: controlledStep,
@@ -45169,9 +45189,13 @@ var init_WizardContainer = __esm({
45169
45189
  showProgress = true,
45170
45190
  allowBack = true,
45171
45191
  compact = false,
45172
- className
45192
+ className,
45193
+ nextEvent,
45194
+ backEvent,
45195
+ completeEvent
45173
45196
  }) => {
45174
45197
  const { t } = hooks.useTranslate();
45198
+ const eventBus = useEventBus();
45175
45199
  const [internalStep, setInternalStep] = React79.useState(0);
45176
45200
  const normalizedControlledStep = (() => {
45177
45201
  if (controlledStep === void 0 || controlledStep === null)
@@ -45201,13 +45225,16 @@ var init_WizardContainer = __esm({
45201
45225
  return;
45202
45226
  }
45203
45227
  if (isLastStep) {
45228
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, { step: currentStep });
45204
45229
  onComplete?.();
45205
45230
  } else {
45231
+ if (nextEvent) eventBus.emit(`UI:${nextEvent}`, { step: currentStep + 1 });
45206
45232
  goToStep(currentStep + 1);
45207
45233
  }
45208
45234
  };
45209
45235
  const handleBack = () => {
45210
45236
  if (!isFirstStep && allowBack) {
45237
+ if (backEvent) eventBus.emit(`UI:${backEvent}`, { step: currentStep - 1 });
45211
45238
  goToStep(currentStep - 1);
45212
45239
  }
45213
45240
  };
@@ -47892,14 +47919,18 @@ var init_DrawerSlot = __esm({
47892
47919
  title: overrideTitle,
47893
47920
  position = "right",
47894
47921
  size = "md",
47895
- className
47922
+ className,
47923
+ sourceTrait
47896
47924
  }) => {
47897
47925
  const eventBus = useEventBus();
47926
+ const schemaCtx = providers.useEntitySchemaOptional();
47898
47927
  const isOpen = Boolean(children);
47899
47928
  const title = overrideTitle || extractTitle(children);
47900
47929
  const handleClose = () => {
47901
- eventBus.emit("UI:CLOSE");
47902
- eventBus.emit("UI:CANCEL");
47930
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
47931
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
47932
+ eventBus.emit(`${prefix}CLOSE`);
47933
+ eventBus.emit(`${prefix}CANCEL`);
47903
47934
  };
47904
47935
  if (!isOpen) return null;
47905
47936
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -49870,14 +49901,18 @@ var init_ModalSlot = __esm({
49870
49901
  children,
49871
49902
  title: overrideTitle,
49872
49903
  size = "md",
49873
- className
49904
+ className,
49905
+ sourceTrait
49874
49906
  }) => {
49875
49907
  const eventBus = useEventBus();
49908
+ const schemaCtx = providers.useEntitySchemaOptional();
49876
49909
  const isOpen = Boolean(children);
49877
49910
  const title = overrideTitle || extractTitle2(children);
49878
49911
  const handleClose = () => {
49879
- eventBus.emit("UI:CLOSE");
49880
- eventBus.emit("UI:CANCEL");
49912
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
49913
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
49914
+ eventBus.emit(`${prefix}CLOSE`);
49915
+ eventBus.emit(`${prefix}CANCEL`);
49881
49916
  };
49882
49917
  if (!isOpen) return null;
49883
49918
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -53442,17 +53477,21 @@ var init_ToastSlot = __esm({
53442
53477
  variant: overrideVariant,
53443
53478
  title: overrideTitle,
53444
53479
  duration = 5e3,
53445
- className
53480
+ className,
53481
+ sourceTrait
53446
53482
  }) => {
53447
53483
  const eventBus = useEventBus();
53484
+ const schemaCtx = providers.useEntitySchemaOptional();
53448
53485
  const isVisible = Boolean(children);
53449
53486
  const extracted = extractToastProps(children);
53450
53487
  const variant = overrideVariant || extracted.variant || "info";
53451
53488
  const title = overrideTitle || extracted.title;
53452
53489
  const message = extracted.message || (typeof children === "string" ? children : "");
53453
53490
  const handleDismiss = () => {
53454
- eventBus.emit("UI:DISMISS");
53455
- eventBus.emit("UI:CLOSE");
53491
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
53492
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
53493
+ eventBus.emit(`${prefix}DISMISS`);
53494
+ eventBus.emit(`${prefix}CLOSE`);
53456
53495
  };
53457
53496
  if (!isVisible) return null;
53458
53497
  const isCustomContent = React79__namespace.default.isValidElement(children) && !message;
@@ -54179,7 +54218,7 @@ function getSlotFallback(slot, config) {
54179
54218
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
54180
54219
  return /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { variant });
54181
54220
  }
54182
- function getComponentForPattern3(patternType) {
54221
+ function getComponentForPattern(patternType) {
54183
54222
  const mapping = patterns.getComponentForPattern(patternType);
54184
54223
  if (!mapping) {
54185
54224
  return null;
@@ -54388,6 +54427,7 @@ function UISlotComponent({
54388
54427
  const { t } = hooks.useTranslate();
54389
54428
  const suspenseConfig = React79.useContext(SuspenseConfigContext);
54390
54429
  const contained = React79.useContext(SlotContainedContext);
54430
+ const schemaCtx = providers.useEntitySchemaOptional();
54391
54431
  const content = slots[slot];
54392
54432
  if (children !== void 0) {
54393
54433
  if (pattern === "clear") {
@@ -54433,8 +54473,11 @@ function UISlotComponent({
54433
54473
  }
54434
54474
  const handleDismiss = () => {
54435
54475
  if (slot === "modal" || slot === "drawer") {
54436
- eventBus.emit("UI:CLOSE");
54437
- eventBus.emit("UI:CANCEL");
54476
+ const trait = content?.sourceTrait;
54477
+ const orbital = trait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(trait) : void 0;
54478
+ const prefix = orbital !== void 0 && trait !== void 0 ? `UI:${orbital}.${trait}.` : "UI:";
54479
+ eventBus.emit(`${prefix}CLOSE`);
54480
+ eventBus.emit(`${prefix}CANCEL`);
54438
54481
  }
54439
54482
  clear(slot);
54440
54483
  };
@@ -54488,6 +54531,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54488
54531
  const slotsBus = context.useUISlots();
54489
54532
  const eventBus = useEventBus();
54490
54533
  const { t } = hooks.useTranslate();
54534
+ const compiledPortalSchemaCtx = providers.useEntitySchemaOptional();
54491
54535
  React79.useEffect(() => {
54492
54536
  setPortalRoot(getOrCreatePortalRoot());
54493
54537
  }, []);
@@ -54496,8 +54540,10 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54496
54540
  });
54497
54541
  const handleDismiss = () => {
54498
54542
  if (slot === "modal" || slot === "drawer") {
54499
- eventBus.emit("UI:CLOSE");
54500
- eventBus.emit("UI:CANCEL");
54543
+ const orbital = sourceTrait !== void 0 && compiledPortalSchemaCtx !== null ? compiledPortalSchemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
54544
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
54545
+ eventBus.emit(`${prefix}CLOSE`);
54546
+ eventBus.emit(`${prefix}CANCEL`);
54501
54547
  }
54502
54548
  slotsBus.clear(slot);
54503
54549
  };
@@ -54809,7 +54855,7 @@ function SlotContentRenderer({
54809
54855
  }
54810
54856
  }
54811
54857
  const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
54812
- const PatternComponent = getComponentForPattern3(content.pattern);
54858
+ const PatternComponent = getComponentForPattern(content.pattern);
54813
54859
  if (PatternComponent) {
54814
54860
  const childrenConfig = content.props.children;
54815
54861
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -55056,6 +55102,7 @@ var init_UISlotRenderer = __esm({
55056
55102
  "custom",
55057
55103
  "dashboard-layout",
55058
55104
  "game-shell",
55105
+ "game-template",
55059
55106
  "scaled-diagram",
55060
55107
  "master-detail",
55061
55108
  "form-field",
@@ -55095,7 +55142,7 @@ function TraitFrame({
55095
55142
  if (!content) {
55096
55143
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
55097
55144
  }
55098
- const SlotContentRenderer2 = getSlotContentRenderer3();
55145
+ const SlotContentRenderer2 = getSlotContentRenderer();
55099
55146
  const rendered = /* @__PURE__ */ jsxRuntime.jsx(
55100
55147
  SlotContentRenderer2,
55101
55148
  {
@@ -55109,7 +55156,7 @@ function TraitFrame({
55109
55156
  }
55110
55157
  return /* @__PURE__ */ jsxRuntime.jsx(providers.TraitScopeProvider, { orbital, trait: traitName, children: rendered });
55111
55158
  }
55112
- function getSlotContentRenderer3() {
55159
+ function getSlotContentRenderer() {
55113
55160
  if (_slotContentRenderer) return _slotContentRenderer;
55114
55161
  const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
55115
55162
  _slotContentRenderer = mod.SlotContentRenderer;