@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 @@ import { isInlineTrait } from '@almadar/core';
40
40
  import { DndContext, useSensors, useSensor, PointerSensor, KeyboardSensor, useDroppable, pointerWithin, rectIntersection, closestCorners } from '@dnd-kit/core';
41
41
  import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
42
42
  import { CSS } from '@dnd-kit/utilities';
43
- import { getPatternDefinition as getPatternDefinition$1, getComponentForPattern } from '@almadar/patterns';
44
43
  import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
44
+ import { getPatternDefinition as getPatternDefinition$1, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
45
45
  import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
46
46
 
47
47
  var __defProp = Object.defineProperty;
@@ -7926,6 +7926,38 @@ var init_Accordion = __esm({
7926
7926
  Accordion.displayName = "Accordion";
7927
7927
  }
7928
7928
  });
7929
+ function GameIcon({ assetUrl, icon, size = "md", alt, className }) {
7930
+ const px = typeof size === "number" ? size : sizeMap[size];
7931
+ if (assetUrl?.url) {
7932
+ return /* @__PURE__ */ jsx(
7933
+ "img",
7934
+ {
7935
+ src: assetUrl.url,
7936
+ alt: alt ?? assetUrl.category ?? "",
7937
+ width: px,
7938
+ height: px,
7939
+ style: { imageRendering: "pixelated", objectFit: "contain", width: px, height: px },
7940
+ className: cn("flex-shrink-0", className)
7941
+ }
7942
+ );
7943
+ }
7944
+ const I = typeof icon === "string" ? resolveIcon(icon) : icon;
7945
+ return /* @__PURE__ */ jsx(I, { width: px, height: px, className: cn("flex-shrink-0", className) });
7946
+ }
7947
+ var sizeMap;
7948
+ var init_GameIcon = __esm({
7949
+ "components/game/2d/atoms/GameIcon.tsx"() {
7950
+ "use client";
7951
+ init_cn();
7952
+ init_Icon();
7953
+ sizeMap = {
7954
+ sm: 16,
7955
+ md: 24,
7956
+ lg: 32
7957
+ };
7958
+ GameIcon.displayName = "GameIcon";
7959
+ }
7960
+ });
7929
7961
  function ActionButton({
7930
7962
  assetUrl = DEFAULT_ASSET_URL,
7931
7963
  label = "Attack",
@@ -7936,18 +7968,23 @@ function ActionButton({
7936
7968
  size = "md",
7937
7969
  variant = "primary",
7938
7970
  onClick,
7971
+ action,
7939
7972
  className
7940
7973
  }) {
7941
- const sizes = sizeMap[size];
7974
+ const eventBus = useEventBus();
7975
+ const sizes = sizeMap2[size];
7942
7976
  const onCooldown = cooldown > 0;
7943
7977
  const isDisabled = disabled || onCooldown;
7944
7978
  const cooldownDeg = Math.round(cooldown * 360);
7945
7979
  return /* @__PURE__ */ jsxs(
7946
- "button",
7980
+ Button,
7947
7981
  {
7948
- type: "button",
7982
+ variant: variant === "danger" ? "danger" : variant === "secondary" ? "secondary" : "primary",
7949
7983
  disabled: isDisabled,
7950
- onClick,
7984
+ onClick: () => {
7985
+ if (action) eventBus.emit(`UI:${action}`, {});
7986
+ onClick?.();
7987
+ },
7951
7988
  className: cn(
7952
7989
  "relative inline-flex items-center gap-1.5 rounded-interactive border font-medium overflow-hidden transition-colors duration-150",
7953
7990
  sizes.button,
@@ -7957,9 +7994,10 @@ function ActionButton({
7957
7994
  ),
7958
7995
  children: [
7959
7996
  onCooldown && /* @__PURE__ */ jsx(
7960
- "div",
7997
+ Box,
7961
7998
  {
7962
- className: "absolute inset-0 bg-foreground/40 pointer-events-none",
7999
+ position: "absolute",
8000
+ className: "inset-0 bg-foreground/40 pointer-events-none",
7963
8001
  style: {
7964
8002
  clipPath: `conic-gradient(from 0deg, transparent ${360 - cooldownDeg}deg, black ${360 - cooldownDeg}deg)`,
7965
8003
  WebkitClipPath: `conic-gradient(from 0deg, transparent ${360 - cooldownDeg}deg, black ${360 - cooldownDeg}deg)`,
@@ -7967,27 +8005,18 @@ function ActionButton({
7967
8005
  }
7968
8006
  }
7969
8007
  ),
7970
- assetUrl ? /* @__PURE__ */ jsx(
7971
- "img",
7972
- {
7973
- src: assetUrl.url,
7974
- alt: "",
7975
- width: 16,
7976
- height: 16,
7977
- style: { imageRendering: "pixelated", objectFit: "contain" },
7978
- className: cn("flex-shrink-0", sizes.icon)
7979
- }
7980
- ) : icon ? /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
8008
+ assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: 16, className: cn("flex-shrink-0", sizes.icon) }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
7981
8009
  const I = resolveIcon(icon);
7982
8010
  return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
7983
8011
  })() : /* @__PURE__ */ (() => {
7984
8012
  const I = icon;
7985
8013
  return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
7986
8014
  })() }) : null,
7987
- /* @__PURE__ */ jsx("span", { className: "relative z-10", children: label }),
8015
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "relative z-10", children: label }),
7988
8016
  hotkey && /* @__PURE__ */ jsx(
7989
- "span",
8017
+ Typography,
7990
8018
  {
8019
+ as: "span",
7991
8020
  className: cn(
7992
8021
  "absolute top-0.5 right-0.5 bg-foreground/30 text-primary-foreground rounded font-mono leading-tight",
7993
8022
  sizes.hotkey
@@ -7999,12 +8028,17 @@ function ActionButton({
7999
8028
  }
8000
8029
  );
8001
8030
  }
8002
- var sizeMap, variantStyles7, DEFAULT_ASSET_URL;
8031
+ var sizeMap2, variantStyles7, DEFAULT_ASSET_URL;
8003
8032
  var init_ActionButton = __esm({
8004
8033
  "components/game/2d/atoms/ActionButton.tsx"() {
8005
8034
  init_cn();
8006
8035
  init_Icon();
8007
- sizeMap = {
8036
+ init_useEventBus();
8037
+ init_Button();
8038
+ init_Box();
8039
+ init_Typography();
8040
+ init_GameIcon();
8041
+ sizeMap2 = {
8008
8042
  sm: { button: "h-button-sm px-3 text-xs", hotkey: "text-[9px] px-1", icon: "text-xs" },
8009
8043
  md: { button: "h-button-md px-4 text-sm", hotkey: "text-xs px-1.5", icon: "text-sm" },
8010
8044
  lg: { button: "h-button-lg px-5 text-base", hotkey: "text-xs px-2", icon: "text-base" }
@@ -8057,7 +8091,7 @@ function ActionTile({
8057
8091
  draggable: !disabled,
8058
8092
  onDragStart: handleDragStart,
8059
8093
  children: [
8060
- action.iconUrl ? /* @__PURE__ */ jsx("img", { src: action.iconUrl, alt: "", className: "w-8 h-8 object-contain" }) : /* @__PURE__ */ jsx(Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8094
+ action.iconUrl ? /* @__PURE__ */ jsx("img", { src: action.iconUrl.url, alt: "", className: "w-8 h-8 object-contain" }) : /* @__PURE__ */ jsx(Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8061
8095
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn(config.text, "text-foreground font-medium whitespace-nowrap"), children: action.name })
8062
8096
  ]
8063
8097
  }
@@ -8661,9 +8695,26 @@ function MiniMap({
8661
8695
  mapWidth = 100,
8662
8696
  mapHeight = 100,
8663
8697
  viewportRect = DEFAULT_VIEWPORT,
8664
- className
8698
+ className,
8699
+ tileAssets,
8700
+ unitAssets
8665
8701
  }) {
8666
8702
  const canvasRef = React79.useRef(null);
8703
+ const imgCacheRef = React79.useRef(/* @__PURE__ */ new Map());
8704
+ function loadImg(url) {
8705
+ const cached = imgCacheRef.current.get(url);
8706
+ if (cached) return cached.complete ? cached : null;
8707
+ const img = new Image();
8708
+ img.src = url;
8709
+ img.onload = () => {
8710
+ const canvas = canvasRef.current;
8711
+ if (!canvas) return;
8712
+ const ctx = canvas.getContext("2d");
8713
+ if (ctx) ctx.clearRect(0, 0, 0, 0);
8714
+ };
8715
+ imgCacheRef.current.set(url, img);
8716
+ return null;
8717
+ }
8667
8718
  React79.useEffect(() => {
8668
8719
  const canvas = canvasRef.current;
8669
8720
  if (!canvas) return;
@@ -8675,20 +8726,31 @@ function MiniMap({
8675
8726
  ctx.fillStyle = "#111";
8676
8727
  ctx.fillRect(0, 0, width, height);
8677
8728
  for (const tile of tiles) {
8678
- ctx.fillStyle = tile.color;
8679
- ctx.fillRect(
8680
- Math.floor(tile.x * scaleX2),
8681
- Math.floor(tile.y * scaleY2),
8682
- Math.max(1, Math.ceil(scaleX2)),
8683
- Math.max(1, Math.ceil(scaleY2))
8684
- );
8729
+ const tileAsset = tileAssets?.[tile.color] ?? tileAssets?.["default"];
8730
+ const tileImg = tileAsset ? loadImg(tileAsset.url) : null;
8731
+ const tx = Math.floor(tile.x * scaleX2);
8732
+ const ty = Math.floor(tile.y * scaleY2);
8733
+ const tw = Math.max(1, Math.ceil(scaleX2));
8734
+ const th = Math.max(1, Math.ceil(scaleY2));
8735
+ if (tileImg) {
8736
+ ctx.drawImage(tileImg, tx, ty, tw, th);
8737
+ } else {
8738
+ ctx.fillStyle = tile.color;
8739
+ ctx.fillRect(tx, ty, tw, th);
8740
+ }
8685
8741
  }
8686
8742
  for (const unit of units) {
8687
8743
  if (unit.isPlayer) continue;
8688
- ctx.fillStyle = unit.color;
8744
+ const unitAsset = unitAssets?.[unit.color] ?? unitAssets?.["default"];
8745
+ const unitImg = unitAsset ? loadImg(unitAsset.url) : null;
8689
8746
  const ux = Math.floor(unit.x * scaleX2) - 1;
8690
8747
  const uy = Math.floor(unit.y * scaleY2) - 1;
8691
- ctx.fillRect(ux, uy, 3, 3);
8748
+ if (unitImg) {
8749
+ ctx.drawImage(unitImg, ux, uy, 5, 5);
8750
+ } else {
8751
+ ctx.fillStyle = unit.color;
8752
+ ctx.fillRect(ux, uy, 3, 3);
8753
+ }
8692
8754
  }
8693
8755
  if (viewportRect) {
8694
8756
  ctx.strokeStyle = "#ffffff";
@@ -8700,7 +8762,7 @@ function MiniMap({
8700
8762
  Math.floor(viewportRect.h * scaleY2)
8701
8763
  );
8702
8764
  }
8703
- }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect]);
8765
+ }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect, tileAssets, unitAssets]);
8704
8766
  const scaleX = width / mapWidth;
8705
8767
  const scaleY = height / mapHeight;
8706
8768
  const playerUnit = units.find((u) => u.isPlayer);
@@ -8709,10 +8771,12 @@ function MiniMap({
8709
8771
  return /* @__PURE__ */ jsxs(Fragment, { children: [
8710
8772
  /* @__PURE__ */ jsx("style", { children: `@keyframes minimap-blink{0%,49%{opacity:1}50%,100%{opacity:0}}` }),
8711
8773
  /* @__PURE__ */ jsxs(
8712
- "div",
8774
+ Box,
8713
8775
  {
8776
+ position: "relative",
8777
+ display: "inline-block",
8714
8778
  className: cn(
8715
- "relative inline-block border border-border/20 rounded-container",
8779
+ "border border-border/20 rounded-container",
8716
8780
  className
8717
8781
  ),
8718
8782
  children: [
@@ -8727,10 +8791,10 @@ function MiniMap({
8727
8791
  }
8728
8792
  ),
8729
8793
  playerLeft !== null && playerTop !== null && /* @__PURE__ */ jsx(
8730
- "div",
8794
+ Box,
8731
8795
  {
8796
+ position: "absolute",
8732
8797
  style: {
8733
- position: "absolute",
8734
8798
  left: playerLeft,
8735
8799
  top: playerTop,
8736
8800
  width: 3,
@@ -8751,6 +8815,7 @@ var init_MiniMap = __esm({
8751
8815
  "components/game/2d/atoms/MiniMap.tsx"() {
8752
8816
  "use client";
8753
8817
  init_cn();
8818
+ init_Box();
8754
8819
  DEFAULT_TILES = [
8755
8820
  { x: 10, y: 10, color: "#4ade80" },
8756
8821
  { x: 20, y: 15, color: "#4ade80" },
@@ -8777,14 +8842,17 @@ function HealthBar({
8777
8842
  labelSuffix,
8778
8843
  size = "md",
8779
8844
  className,
8780
- animated = true
8845
+ animated = true,
8846
+ frameAsset,
8847
+ fillAsset
8781
8848
  }) {
8782
- const sizes = sizeMap2[size];
8849
+ const sizes = sizeMap3[size];
8783
8850
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
8784
8851
  if (format === "hearts") {
8785
- return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1", className), children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsx(
8786
- "span",
8852
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center gap-1", className), children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsx(
8853
+ Box,
8787
8854
  {
8855
+ as: "span",
8788
8856
  className: cn(animated && "transition-transform hover:scale-110"),
8789
8857
  children: heartIcon(i < current, sizes.heart)
8790
8858
  },
@@ -8793,33 +8861,42 @@ function HealthBar({
8793
8861
  }
8794
8862
  if (format === "bar") {
8795
8863
  return /* @__PURE__ */ jsx(
8796
- "div",
8864
+ Box,
8797
8865
  {
8866
+ position: "relative",
8867
+ overflow: "hidden",
8798
8868
  className: cn(
8799
- "relative overflow-hidden rounded-full bg-muted",
8869
+ "rounded-full",
8870
+ !frameAsset && "bg-muted",
8800
8871
  sizes.bar,
8801
8872
  "w-24",
8802
8873
  className
8803
8874
  ),
8875
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8804
8876
  children: /* @__PURE__ */ jsx(
8805
- "div",
8877
+ Box,
8806
8878
  {
8879
+ position: "absolute",
8807
8880
  className: cn(
8808
- "absolute inset-y-0 left-0 rounded-full",
8809
- percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error",
8881
+ "inset-y-0 left-0 rounded-full",
8882
+ !fillAsset && (percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error"),
8810
8883
  animated && "transition-all duration-300"
8811
8884
  ),
8812
- style: { width: `${percentage}%` }
8885
+ style: {
8886
+ width: `${percentage}%`,
8887
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8888
+ }
8813
8889
  }
8814
8890
  )
8815
8891
  }
8816
8892
  );
8817
8893
  }
8818
8894
  if (format === "progress") {
8819
- return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), children: [
8895
+ return /* @__PURE__ */ jsxs(Box, { className: cn("flex items-center gap-2", className), children: [
8820
8896
  level != null && /* @__PURE__ */ jsxs(
8821
- "span",
8897
+ Typography,
8822
8898
  {
8899
+ as: "span",
8823
8900
  className: cn(
8824
8901
  "flex-shrink-0 rounded-interactive font-bold",
8825
8902
  "bg-accent text-accent-foreground border border-accent",
@@ -8831,28 +8908,35 @@ function HealthBar({
8831
8908
  ]
8832
8909
  }
8833
8910
  ),
8834
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [
8911
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 flex flex-col gap-0.5", children: [
8835
8912
  /* @__PURE__ */ jsx(
8836
- "div",
8913
+ Box,
8837
8914
  {
8915
+ position: "relative",
8838
8916
  className: cn(
8839
- "relative w-full overflow-hidden rounded-full bg-muted border border-muted",
8917
+ "w-full overflow-hidden rounded-full",
8918
+ !frameAsset && "bg-muted border border-muted",
8840
8919
  sizes.bar
8841
8920
  ),
8921
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8842
8922
  children: /* @__PURE__ */ jsx(
8843
- "div",
8923
+ Box,
8844
8924
  {
8925
+ position: "absolute",
8845
8926
  className: cn(
8846
- "absolute inset-y-0 left-0 rounded-full",
8847
- "bg-gradient-to-r from-accent to-info",
8927
+ "inset-y-0 left-0 rounded-full",
8928
+ !fillAsset && "bg-gradient-to-r from-accent to-info",
8848
8929
  animated && "transition-all duration-500 ease-out"
8849
8930
  ),
8850
- style: { width: `${percentage}%` }
8931
+ style: {
8932
+ width: `${percentage}%`,
8933
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8934
+ }
8851
8935
  }
8852
8936
  )
8853
8937
  }
8854
8938
  ),
8855
- showLabel && /* @__PURE__ */ jsxs("span", { className: cn("text-foreground/70 tabular-nums", sizes.label), children: [
8939
+ showLabel && /* @__PURE__ */ jsxs(Typography, { as: "span", className: cn("text-foreground/70 tabular-nums", sizes.label), children: [
8856
8940
  current,
8857
8941
  " / ",
8858
8942
  max,
@@ -8861,16 +8945,18 @@ function HealthBar({
8861
8945
  ] })
8862
8946
  ] });
8863
8947
  }
8864
- return /* @__PURE__ */ jsxs("span", { className: cn("font-mono font-bold", sizes.text, className), children: [
8948
+ return /* @__PURE__ */ jsxs(Typography, { as: "span", className: cn("font-mono font-bold", sizes.text, className), children: [
8865
8949
  current,
8866
8950
  "/",
8867
8951
  max
8868
8952
  ] });
8869
8953
  }
8870
- var heartIcon, sizeMap2;
8954
+ var heartIcon, sizeMap3;
8871
8955
  var init_HealthBar = __esm({
8872
8956
  "components/game/2d/atoms/HealthBar.tsx"() {
8873
8957
  init_cn();
8958
+ init_Box();
8959
+ init_Typography();
8874
8960
  heartIcon = (filled, size) => /* @__PURE__ */ jsx(
8875
8961
  "svg",
8876
8962
  {
@@ -8882,7 +8968,7 @@ var init_HealthBar = __esm({
8882
8968
  children: /* @__PURE__ */ 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" })
8883
8969
  }
8884
8970
  );
8885
- sizeMap2 = {
8971
+ sizeMap3 = {
8886
8972
  sm: { heart: "w-4 h-4", bar: "h-2", text: "text-sm", label: "text-xs", badge: "text-xs px-1.5 py-0.5" },
8887
8973
  md: { heart: "w-6 h-6", bar: "h-3", text: "text-base", label: "text-xs", badge: "text-xs px-2 py-0.5" },
8888
8974
  lg: { heart: "w-8 h-8", bar: "h-4", text: "text-lg", label: "text-sm", badge: "text-sm px-2.5 py-1" }
@@ -10670,10 +10756,11 @@ function Canvas2D({
10670
10756
  }
10671
10757
  }
10672
10758
  ),
10673
- process.env.NODE_ENV !== "production" && /* @__PURE__ */ jsxs("div", { "data-game-actions": "", className: "sr-only", "aria-hidden": "true", children: [
10759
+ process.env.NODE_ENV !== "production" && /* @__PURE__ */ jsxs(Box, { "data-game-actions": "", className: "sr-only", "aria-hidden": "true", children: [
10674
10760
  tileClickEvent && /* @__PURE__ */ jsx(
10675
- "button",
10761
+ Button,
10676
10762
  {
10763
+ variant: "ghost",
10677
10764
  "data-event": tileClickEvent,
10678
10765
  "data-x": "0",
10679
10766
  "data-y": "0",
@@ -10682,8 +10769,9 @@ function Canvas2D({
10682
10769
  }
10683
10770
  ),
10684
10771
  unitClickEvent && units && units.length > 0 && /* @__PURE__ */ jsx(
10685
- "button",
10772
+ Button,
10686
10773
  {
10774
+ variant: "ghost",
10687
10775
  "data-event": unitClickEvent,
10688
10776
  "data-unit-id": units[0].id,
10689
10777
  onClick: () => eventBus.emit(`UI:${unitClickEvent}`, { unitId: units[0].id }),
@@ -10692,15 +10780,17 @@ function Canvas2D({
10692
10780
  )
10693
10781
  ] }),
10694
10782
  unitOverlays.map(({ unit, screenX, screenY }) => /* @__PURE__ */ jsxs(
10695
- "div",
10783
+ Box,
10696
10784
  {
10697
- className: "absolute pointer-events-none",
10785
+ position: "absolute",
10786
+ className: "pointer-events-none",
10698
10787
  style: { left: Math.round(screenX), top: Math.round(screenY), transform: "translate(-50%, 0)", zIndex: 5 },
10699
10788
  children: [
10700
10789
  unit.name && /* @__PURE__ */ jsx(
10701
- "div",
10790
+ Typography,
10702
10791
  {
10703
- className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap",
10792
+ as: "span",
10793
+ className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap block",
10704
10794
  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)" },
10705
10795
  children: unit.name
10706
10796
  }
@@ -10710,7 +10800,7 @@ function Canvas2D({
10710
10800
  },
10711
10801
  unit.id
10712
10802
  )),
10713
- showMinimap && /* @__PURE__ */ jsx("div", { className: "absolute bottom-2 right-2 pointer-events-none", style: { zIndex: 10 }, children: /* @__PURE__ */ jsx(
10803
+ showMinimap && /* @__PURE__ */ jsx(Box, { position: "absolute", className: "bottom-2 right-2 pointer-events-none", style: { zIndex: 10 }, children: /* @__PURE__ */ jsx(
10714
10804
  MiniMap,
10715
10805
  {
10716
10806
  tiles: miniMapTiles,
@@ -10732,6 +10822,7 @@ var init_Canvas2D = __esm({
10732
10822
  init_cn();
10733
10823
  init_useEventBus();
10734
10824
  init_Box();
10825
+ init_Button();
10735
10826
  init_Stack();
10736
10827
  init_Icon();
10737
10828
  init_Typography();
@@ -12629,9 +12720,9 @@ var init_BiologyCanvas = __esm({
12629
12720
  }
12630
12721
  });
12631
12722
 
12632
- // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
12723
+ // node_modules/katex/dist/katex.min.css
12633
12724
  var init_katex_min = __esm({
12634
- "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
12725
+ "node_modules/katex/dist/katex.min.css"() {
12635
12726
  }
12636
12727
  });
12637
12728
  var Tabs;
@@ -17109,38 +17200,6 @@ var init_Breadcrumb = __esm({
17109
17200
  Breadcrumb.displayName = "Breadcrumb";
17110
17201
  }
17111
17202
  });
17112
- function GameIcon({ assetUrl, icon, size = "md", alt, className }) {
17113
- const px = typeof size === "number" ? size : sizeMap3[size];
17114
- if (assetUrl?.url) {
17115
- return /* @__PURE__ */ jsx(
17116
- "img",
17117
- {
17118
- src: assetUrl.url,
17119
- alt: alt ?? assetUrl.category ?? "",
17120
- width: px,
17121
- height: px,
17122
- style: { imageRendering: "pixelated", objectFit: "contain", width: px, height: px },
17123
- className: cn("flex-shrink-0", className)
17124
- }
17125
- );
17126
- }
17127
- const I = typeof icon === "string" ? resolveIcon(icon) : icon;
17128
- return /* @__PURE__ */ jsx(I, { width: px, height: px, className: cn("flex-shrink-0", className) });
17129
- }
17130
- var sizeMap3;
17131
- var init_GameIcon = __esm({
17132
- "components/game/2d/atoms/GameIcon.tsx"() {
17133
- "use client";
17134
- init_cn();
17135
- init_Icon();
17136
- sizeMap3 = {
17137
- sm: 16,
17138
- md: 24,
17139
- lg: 32
17140
- };
17141
- GameIcon.displayName = "GameIcon";
17142
- }
17143
- });
17144
17203
  function BuilderBoard({
17145
17204
  entity,
17146
17205
  completeEvent = "PUZZLE_COMPLETE",
@@ -18972,9 +19031,9 @@ function GameCard({
18972
19031
  }, [disabled, id, onClick, clickEvent, eventBus]);
18973
19032
  const artPx = artPxMap[size];
18974
19033
  return /* @__PURE__ */ jsxs(
18975
- "button",
19034
+ Button,
18976
19035
  {
18977
- type: "button",
19036
+ variant: "ghost",
18978
19037
  onClick: handleClick,
18979
19038
  disabled,
18980
19039
  title: name,
@@ -18988,8 +19047,9 @@ function GameCard({
18988
19047
  ),
18989
19048
  children: [
18990
19049
  cost != null && /* @__PURE__ */ jsx(
18991
- "span",
19050
+ Typography,
18992
19051
  {
19052
+ as: "span",
18993
19053
  className: cn(
18994
19054
  "absolute -top-2 -left-2 flex items-center justify-center",
18995
19055
  "min-w-[22px] h-[22px] rounded-full px-1",
@@ -18998,17 +19058,7 @@ function GameCard({
18998
19058
  children: cost
18999
19059
  }
19000
19060
  ),
19001
- /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: art ? /* @__PURE__ */ jsx(
19002
- "img",
19003
- {
19004
- src: art.url,
19005
- alt: name ?? id,
19006
- width: artPx,
19007
- height: artPx,
19008
- style: { imageRendering: "pixelated", objectFit: "contain" },
19009
- className: "flex-shrink-0"
19010
- }
19011
- ) : /* @__PURE__ */ jsx(Box, { className: "rounded bg-muted/40", style: { width: artPx, height: artPx } }) }),
19061
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: art ? /* @__PURE__ */ jsx(GameIcon, { assetUrl: art, icon: "image", size: artPx, alt: name ?? id, className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(Box, { className: "rounded bg-muted/40", style: { width: artPx, height: artPx } }) }),
19012
19062
  name != null && /* @__PURE__ */ jsx(
19013
19063
  Typography,
19014
19064
  {
@@ -19018,8 +19068,8 @@ function GameCard({
19018
19068
  }
19019
19069
  ),
19020
19070
  (attack != null || defense != null) && /* @__PURE__ */ jsxs(Box, { className: "flex w-full items-center justify-between px-0.5 text-[10px] font-bold leading-none", children: [
19021
- /* @__PURE__ */ jsx("span", { className: "text-error", children: attack != null ? `\u2694${attack}` : "" }),
19022
- /* @__PURE__ */ jsx("span", { className: "text-info", children: defense != null ? `\u{1F6E1}${defense}` : "" })
19071
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-error", children: attack != null ? `\u2694${attack}` : "" }),
19072
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-info", children: defense != null ? `\u{1F6E1}${defense}` : "" })
19023
19073
  ] })
19024
19074
  ]
19025
19075
  }
@@ -19032,7 +19082,9 @@ var init_GameCard = __esm({
19032
19082
  init_cn();
19033
19083
  init_useEventBus();
19034
19084
  init_Box();
19085
+ init_Button();
19035
19086
  init_Typography();
19087
+ init_GameIcon();
19036
19088
  cardSizeMap = {
19037
19089
  sm: "w-16 h-24",
19038
19090
  md: "w-20 h-28",
@@ -21438,14 +21490,19 @@ function ChoiceButton({
21438
21490
  disabled = false,
21439
21491
  selected = false,
21440
21492
  onClick,
21493
+ action,
21441
21494
  className
21442
21495
  }) {
21496
+ const eventBus = useEventBus();
21443
21497
  return /* @__PURE__ */ jsxs(
21444
- "button",
21498
+ Button,
21445
21499
  {
21446
- type: "button",
21500
+ variant: "ghost",
21447
21501
  disabled,
21448
- onClick,
21502
+ onClick: () => {
21503
+ if (action) eventBus.emit(`UI:${action}`, {});
21504
+ onClick?.();
21505
+ },
21449
21506
  className: cn(
21450
21507
  "w-full text-left px-4 py-2.5 rounded-interactive border transition-all duration-150",
21451
21508
  "flex items-center gap-2",
@@ -21455,8 +21512,9 @@ function ChoiceButton({
21455
21512
  ),
21456
21513
  children: [
21457
21514
  index !== void 0 && /* @__PURE__ */ jsxs(
21458
- "span",
21515
+ Typography,
21459
21516
  {
21517
+ as: "span",
21460
21518
  className: cn(
21461
21519
  "flex-shrink-0 font-mono font-bold text-sm",
21462
21520
  selected ? "text-accent" : "text-muted-foreground"
@@ -21467,24 +21525,14 @@ function ChoiceButton({
21467
21525
  ]
21468
21526
  }
21469
21527
  ),
21470
- assetUrl ? /* @__PURE__ */ jsx(
21471
- "img",
21472
- {
21473
- src: assetUrl.url,
21474
- alt: "",
21475
- width: 16,
21476
- height: 16,
21477
- style: { imageRendering: "pixelated", objectFit: "contain" },
21478
- className: "flex-shrink-0"
21479
- }
21480
- ) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
21528
+ assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: 16, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
21481
21529
  const I = resolveIcon(icon);
21482
21530
  return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
21483
21531
  })() : /* @__PURE__ */ (() => {
21484
21532
  const I = icon;
21485
21533
  return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
21486
21534
  })() }) : null,
21487
- /* @__PURE__ */ jsx("span", { className: "text-sm leading-snug", children: text })
21535
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-sm leading-snug", children: text })
21488
21536
  ]
21489
21537
  }
21490
21538
  );
@@ -21493,6 +21541,11 @@ var init_ChoiceButton = __esm({
21493
21541
  "components/game/2d/atoms/ChoiceButton.tsx"() {
21494
21542
  init_cn();
21495
21543
  init_Icon();
21544
+ init_useEventBus();
21545
+ init_Button();
21546
+ init_Box();
21547
+ init_Typography();
21548
+ init_GameIcon();
21496
21549
  ChoiceButton.displayName = "ChoiceButton";
21497
21550
  }
21498
21551
  });
@@ -22170,7 +22223,7 @@ function ComboCounter({
22170
22223
  const sizes = sizeMap4[size];
22171
22224
  if (combo <= 0) return null;
22172
22225
  return /* @__PURE__ */ jsxs(
22173
- "div",
22226
+ Box,
22174
22227
  {
22175
22228
  className: cn(
22176
22229
  "inline-flex flex-col items-center justify-center",
@@ -22180,24 +22233,14 @@ function ComboCounter({
22180
22233
  className
22181
22234
  ),
22182
22235
  children: [
22183
- assetUrl && /* @__PURE__ */ jsx(
22184
- "img",
22185
- {
22186
- src: assetUrl.url,
22187
- alt: "combo",
22188
- width: 24,
22189
- height: 24,
22190
- style: { imageRendering: "pixelated", objectFit: "contain" },
22191
- className: "flex-shrink-0 mb-0.5"
22192
- }
22193
- ),
22194
- /* @__PURE__ */ jsx("span", { className: cn("font-black tabular-nums leading-none", sizes.combo, getComboIntensity(combo)), children: combo }),
22195
- /* @__PURE__ */ jsx("span", { className: cn("font-bold uppercase tracking-wider text-muted-foreground", sizes.label), children: "combo" }),
22196
- multiplier != null && multiplier > 1 && /* @__PURE__ */ jsxs("span", { className: cn("font-bold text-warning tabular-nums", sizes.multiplier), children: [
22236
+ assetUrl && /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: 24, className: "flex-shrink-0 mb-0.5" }),
22237
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: cn("font-black tabular-nums leading-none", sizes.combo, getComboIntensity(combo)), children: combo }),
22238
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: cn("font-bold uppercase tracking-wider text-muted-foreground", sizes.label), children: "combo" }),
22239
+ multiplier != null && multiplier > 1 && /* @__PURE__ */ jsxs(Typography, { as: "span", className: cn("font-bold text-warning tabular-nums", sizes.multiplier), children: [
22197
22240
  "x",
22198
22241
  multiplier.toFixed(1)
22199
22242
  ] }),
22200
- streak != null && streak > 0 && /* @__PURE__ */ jsxs("span", { className: cn("text-muted-foreground tabular-nums", sizes.label), children: [
22243
+ streak != null && streak > 0 && /* @__PURE__ */ jsxs(Typography, { as: "span", className: cn("text-muted-foreground tabular-nums", sizes.label), children: [
22201
22244
  streak,
22202
22245
  " streak"
22203
22246
  ] })
@@ -22209,6 +22252,9 @@ var DEFAULT_ASSET_URL2, sizeMap4;
22209
22252
  var init_ComboCounter = __esm({
22210
22253
  "components/game/2d/atoms/ComboCounter.tsx"() {
22211
22254
  init_cn();
22255
+ init_Box();
22256
+ init_Typography();
22257
+ init_GameIcon();
22212
22258
  DEFAULT_ASSET_URL2 = {
22213
22259
  url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
22214
22260
  role: "effect",
@@ -22458,9 +22504,9 @@ function ControlButton({
22458
22504
  [isPressed, releaseEvent, eventBus, onRelease]
22459
22505
  );
22460
22506
  return /* @__PURE__ */ jsx(
22461
- "button",
22507
+ Button,
22462
22508
  {
22463
- type: "button",
22509
+ variant,
22464
22510
  disabled,
22465
22511
  onPointerDown: handlePointerDown,
22466
22512
  onPointerUp: handlePointerUp,
@@ -22478,23 +22524,13 @@ function ControlButton({
22478
22524
  disabled && "opacity-50 cursor-not-allowed",
22479
22525
  className
22480
22526
  ),
22481
- children: assetUrl ? /* @__PURE__ */ jsx(
22482
- "img",
22483
- {
22484
- src: assetUrl.url,
22485
- alt: "",
22486
- width: 24,
22487
- height: 24,
22488
- style: { imageRendering: "pixelated", objectFit: "contain" },
22489
- className: "flex-shrink-0"
22490
- }
22491
- ) : icon ? /* @__PURE__ */ jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
22527
+ children: assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: 24, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
22492
22528
  const I = resolveIcon(icon);
22493
22529
  return I ? /* @__PURE__ */ jsx(I, { className: "w-6 h-6" }) : null;
22494
22530
  })() : icon : /* @__PURE__ */ (() => {
22495
22531
  const I = icon;
22496
22532
  return /* @__PURE__ */ jsx(I, { className: "w-6 h-6" });
22497
- })() }) : label ? /* @__PURE__ */ jsx("span", { children: label }) : null
22533
+ })() }) : label ? /* @__PURE__ */ jsx(Typography, { as: "span", children: label }) : null
22498
22534
  }
22499
22535
  );
22500
22536
  }
@@ -22505,6 +22541,10 @@ var init_ControlButton = __esm({
22505
22541
  init_cn();
22506
22542
  init_useEventBus();
22507
22543
  init_Icon();
22544
+ init_Button();
22545
+ init_Box();
22546
+ init_Typography();
22547
+ init_GameIcon();
22508
22548
  sizeMap5 = {
22509
22549
  sm: "w-10 h-10 text-sm",
22510
22550
  md: "w-14 h-14 text-base",
@@ -22538,6 +22578,7 @@ function ControlGrid({
22538
22578
  actionEvent,
22539
22579
  onDirection,
22540
22580
  directionEvent,
22581
+ directionAssets,
22541
22582
  size = "md",
22542
22583
  disabled,
22543
22584
  className
@@ -22577,7 +22618,8 @@ function ControlGrid({
22577
22618
  const dir = (d) => /* @__PURE__ */ jsx(
22578
22619
  ControlButton,
22579
22620
  {
22580
- icon: arrowIcons[d],
22621
+ icon: directionAssets?.[d] ? void 0 : arrowIcons[d],
22622
+ assetUrl: directionAssets?.[d],
22581
22623
  size: sizeKey[size],
22582
22624
  variant: "secondary",
22583
22625
  pressed: active.has(d),
@@ -22587,22 +22629,22 @@ function ControlGrid({
22587
22629
  },
22588
22630
  d
22589
22631
  );
22590
- return /* @__PURE__ */ jsxs("div", { className: cn("inline-grid grid-cols-3", ds.gap, ds.container, className), children: [
22591
- /* @__PURE__ */ jsx("div", {}),
22632
+ return /* @__PURE__ */ jsxs(Box, { className: cn("inline-grid grid-cols-3", ds.gap, ds.container, className), children: [
22633
+ /* @__PURE__ */ jsx(Box, {}),
22592
22634
  dir("up"),
22593
- /* @__PURE__ */ jsx("div", {}),
22635
+ /* @__PURE__ */ jsx(Box, {}),
22594
22636
  dir("left"),
22595
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 rounded-interactive bg-muted border-2 border-muted-foreground" }) }),
22637
+ /* @__PURE__ */ jsx(Box, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(Box, { className: "w-6 h-6 rounded-interactive bg-muted border-2 border-muted-foreground" }) }),
22596
22638
  dir("right"),
22597
- /* @__PURE__ */ jsx("div", {}),
22639
+ /* @__PURE__ */ jsx(Box, {}),
22598
22640
  dir("down"),
22599
- /* @__PURE__ */ jsx("div", {})
22641
+ /* @__PURE__ */ jsx(Box, {})
22600
22642
  ] });
22601
22643
  }
22602
22644
  if (layout === "diamond" && buttons.length === 4) {
22603
22645
  const [top, right, bottom, left] = buttons;
22604
- return /* @__PURE__ */ jsxs("div", { className: cn(layoutClass.diamond, className), children: [
22605
- /* @__PURE__ */ jsx("div", {}),
22646
+ return /* @__PURE__ */ jsxs(Box, { className: cn(layoutClass.diamond, className), children: [
22647
+ /* @__PURE__ */ jsx(Box, {}),
22606
22648
  /* @__PURE__ */ jsx(
22607
22649
  ControlButton,
22608
22650
  {
@@ -22617,7 +22659,7 @@ function ControlGrid({
22617
22659
  disabled
22618
22660
  }
22619
22661
  ),
22620
- /* @__PURE__ */ jsx("div", {}),
22662
+ /* @__PURE__ */ jsx(Box, {}),
22621
22663
  /* @__PURE__ */ jsx(
22622
22664
  ControlButton,
22623
22665
  {
@@ -22632,7 +22674,7 @@ function ControlGrid({
22632
22674
  disabled
22633
22675
  }
22634
22676
  ),
22635
- /* @__PURE__ */ jsx("div", {}),
22677
+ /* @__PURE__ */ jsx(Box, {}),
22636
22678
  /* @__PURE__ */ jsx(
22637
22679
  ControlButton,
22638
22680
  {
@@ -22647,7 +22689,7 @@ function ControlGrid({
22647
22689
  disabled
22648
22690
  }
22649
22691
  ),
22650
- /* @__PURE__ */ jsx("div", {}),
22692
+ /* @__PURE__ */ jsx(Box, {}),
22651
22693
  /* @__PURE__ */ jsx(
22652
22694
  ControlButton,
22653
22695
  {
@@ -22662,10 +22704,10 @@ function ControlGrid({
22662
22704
  disabled
22663
22705
  }
22664
22706
  ),
22665
- /* @__PURE__ */ jsx("div", {})
22707
+ /* @__PURE__ */ jsx(Box, {})
22666
22708
  ] });
22667
22709
  }
22668
- return /* @__PURE__ */ jsx("div", { className: cn(layoutClass[layout], className), children: buttons.map((button) => /* @__PURE__ */ jsx(
22710
+ return /* @__PURE__ */ jsx(Box, { className: cn(layoutClass[layout], className), children: buttons.map((button) => /* @__PURE__ */ jsx(
22669
22711
  ControlButton,
22670
22712
  {
22671
22713
  icon: button.icon,
@@ -22687,6 +22729,7 @@ var init_ControlGrid = __esm({
22687
22729
  "use client";
22688
22730
  init_cn();
22689
22731
  init_useEventBus();
22732
+ init_Box();
22690
22733
  init_ControlButton();
22691
22734
  sizeKey = { sm: "sm", md: "md", lg: "lg" };
22692
22735
  layoutClass = {
@@ -22718,6 +22761,8 @@ function CounterMinimal({
22718
22761
  size = "md",
22719
22762
  onDecrement,
22720
22763
  onIncrement,
22764
+ decrementEvent,
22765
+ incrementEvent,
22721
22766
  className
22722
22767
  }) {
22723
22768
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22728,6 +22773,7 @@ function CounterMinimal({
22728
22773
  {
22729
22774
  variant: "secondary",
22730
22775
  size: sizeStyles8[size].button,
22776
+ action: decrementEvent,
22731
22777
  onClick: onDecrement,
22732
22778
  disabled: resolved.decrementDisabled,
22733
22779
  icon: "minus",
@@ -22750,6 +22796,7 @@ function CounterMinimal({
22750
22796
  {
22751
22797
  variant: "secondary",
22752
22798
  size: sizeStyles8[size].button,
22799
+ action: incrementEvent,
22753
22800
  onClick: onIncrement,
22754
22801
  disabled: resolved.incrementDisabled,
22755
22802
  icon: "plus",
@@ -22766,6 +22813,9 @@ function CounterStandard({
22766
22813
  onDecrement,
22767
22814
  onIncrement,
22768
22815
  onReset,
22816
+ decrementEvent,
22817
+ incrementEvent,
22818
+ resetEvent,
22769
22819
  className
22770
22820
  }) {
22771
22821
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22796,6 +22846,7 @@ function CounterStandard({
22796
22846
  {
22797
22847
  variant: "secondary",
22798
22848
  size: sizeStyles8[size].button,
22849
+ action: decrementEvent,
22799
22850
  onClick: onDecrement,
22800
22851
  disabled: resolved.decrementDisabled,
22801
22852
  icon: "minus"
@@ -22806,6 +22857,7 @@ function CounterStandard({
22806
22857
  {
22807
22858
  variant: "primary",
22808
22859
  size: sizeStyles8[size].button,
22860
+ action: incrementEvent,
22809
22861
  onClick: onIncrement,
22810
22862
  disabled: resolved.incrementDisabled,
22811
22863
  icon: "plus"
@@ -22817,6 +22869,7 @@ function CounterStandard({
22817
22869
  {
22818
22870
  variant: "ghost",
22819
22871
  size: "sm",
22872
+ action: resetEvent,
22820
22873
  onClick: onReset,
22821
22874
  icon: "rotate-ccw",
22822
22875
  children: "Reset"
@@ -22832,6 +22885,9 @@ function CounterFull({
22832
22885
  onDecrement,
22833
22886
  onIncrement,
22834
22887
  onReset,
22888
+ decrementEvent,
22889
+ incrementEvent,
22890
+ resetEvent,
22835
22891
  className
22836
22892
  }) {
22837
22893
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22865,6 +22921,7 @@ function CounterFull({
22865
22921
  {
22866
22922
  variant: "secondary",
22867
22923
  size: sizeStyles8[size].button,
22924
+ action: decrementEvent,
22868
22925
  onClick: onDecrement,
22869
22926
  disabled: resolved.decrementDisabled,
22870
22927
  icon: "minus",
@@ -22876,6 +22933,7 @@ function CounterFull({
22876
22933
  {
22877
22934
  variant: "primary",
22878
22935
  size: sizeStyles8[size].button,
22936
+ action: incrementEvent,
22879
22937
  onClick: onIncrement,
22880
22938
  disabled: resolved.incrementDisabled,
22881
22939
  icon: "plus",
@@ -22888,6 +22946,7 @@ function CounterFull({
22888
22946
  {
22889
22947
  variant: "ghost",
22890
22948
  size: "sm",
22949
+ action: resetEvent,
22891
22950
  onClick: onReset,
22892
22951
  icon: "rotate-ccw",
22893
22952
  children: "Reset to 0"
@@ -22935,8 +22994,9 @@ function DamageNumber({
22935
22994
  return /* @__PURE__ */ jsxs(Fragment, { children: [
22936
22995
  /* @__PURE__ */ jsx("style", { children: floatKeyframes }),
22937
22996
  /* @__PURE__ */ jsxs(
22938
- "span",
22997
+ Typography,
22939
22998
  {
22999
+ as: "span",
22940
23000
  className: cn(
22941
23001
  "inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
22942
23002
  sizeMap6[size],
@@ -22945,17 +23005,7 @@ function DamageNumber({
22945
23005
  ),
22946
23006
  style: { animation: "damageFloat 1s ease-out forwards" },
22947
23007
  children: [
22948
- assetUrl && /* @__PURE__ */ jsx(
22949
- "img",
22950
- {
22951
- src: assetUrl.url,
22952
- alt: "",
22953
- width: 14,
22954
- height: 14,
22955
- style: { imageRendering: "pixelated", objectFit: "contain" },
22956
- className: "flex-shrink-0"
22957
- }
22958
- ),
23008
+ assetUrl && /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: 14, className: "flex-shrink-0" }),
22959
23009
  displayText
22960
23010
  ]
22961
23011
  }
@@ -22966,6 +23016,8 @@ var sizeMap6, typeStyles, floatKeyframes, DEFAULT_ASSET_URL4;
22966
23016
  var init_DamageNumber = __esm({
22967
23017
  "components/game/2d/atoms/DamageNumber.tsx"() {
22968
23018
  init_cn();
23019
+ init_Typography();
23020
+ init_GameIcon();
22969
23021
  sizeMap6 = {
22970
23022
  sm: "text-sm",
22971
23023
  md: "text-lg",
@@ -29327,7 +29379,7 @@ function ScoreDisplay({
29327
29379
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof score === "number" && !Number.isNaN(score) ? score : 0;
29328
29380
  const formattedValue = new Intl.NumberFormat(locale).format(resolvedValue);
29329
29381
  return /* @__PURE__ */ jsxs(
29330
- "div",
29382
+ Box,
29331
29383
  {
29332
29384
  className: cn(
29333
29385
  "flex items-center gap-2 font-bold",
@@ -29335,19 +29387,9 @@ function ScoreDisplay({
29335
29387
  className
29336
29388
  ),
29337
29389
  children: [
29338
- assetUrl ? /* @__PURE__ */ jsx(
29339
- "img",
29340
- {
29341
- src: assetUrl.url,
29342
- alt: "",
29343
- width: 20,
29344
- height: 20,
29345
- style: { imageRendering: "pixelated", objectFit: "contain" },
29346
- className: "flex-shrink-0"
29347
- }
29348
- ) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
29349
- label && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
29350
- /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formattedValue })
29390
+ assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: 20, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
29391
+ label && /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground", children: label }),
29392
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "tabular-nums", children: formattedValue })
29351
29393
  ]
29352
29394
  }
29353
29395
  );
@@ -29357,6 +29399,9 @@ var init_ScoreDisplay = __esm({
29357
29399
  "components/game/2d/atoms/ScoreDisplay.tsx"() {
29358
29400
  init_cn();
29359
29401
  init_Icon();
29402
+ init_Box();
29403
+ init_Typography();
29404
+ init_GameIcon();
29360
29405
  sizeMap8 = {
29361
29406
  sm: "text-sm",
29362
29407
  md: "text-lg",
@@ -29417,12 +29462,12 @@ function Sprite({
29417
29462
  onClick?.();
29418
29463
  };
29419
29464
  return /* @__PURE__ */ jsx(
29420
- "div",
29465
+ Box,
29421
29466
  {
29467
+ position: "absolute",
29422
29468
  className,
29423
29469
  onClick: action || onClick ? handleClick : void 0,
29424
29470
  style: {
29425
- position: "absolute",
29426
29471
  width: frameWidth,
29427
29472
  height: frameHeight,
29428
29473
  backgroundImage: `url(${spritesheet.url})`,
@@ -29478,6 +29523,7 @@ var init_Sprite = __esm({
29478
29523
  "components/game/2d/atoms/Sprite.tsx"() {
29479
29524
  "use client";
29480
29525
  init_useEventBus();
29526
+ init_Box();
29481
29527
  init_spriteAnimation();
29482
29528
  DEFAULT_SPRITESHEET = {
29483
29529
  url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
@@ -29514,17 +29560,7 @@ function StateIndicator({
29514
29560
  className
29515
29561
  ),
29516
29562
  children: [
29517
- /* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsx(
29518
- "img",
29519
- {
29520
- src: assetUrl.url,
29521
- alt: displayLabel,
29522
- width: 16,
29523
- height: 16,
29524
- style: { imageRendering: "pixelated", objectFit: "contain" },
29525
- className: "flex-shrink-0"
29526
- }
29527
- ) : typeof config.icon === "string" ? /^[a-zA-Z0-9-]+$/.test(config.icon) ? /* @__PURE__ */ jsx(Icon, { name: config.icon }) : config.icon : /* @__PURE__ */ jsx(Icon, { icon: config.icon }) }),
29563
+ /* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ 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__ */ jsx(Icon, { name: config.icon }) : config.icon : /* @__PURE__ */ jsx(Icon, { icon: config.icon }) }),
29528
29564
  /* @__PURE__ */ jsx(Box, { as: "span", children: displayLabel })
29529
29565
  ]
29530
29566
  }
@@ -29536,6 +29572,7 @@ var init_StateIndicator = __esm({
29536
29572
  init_Box();
29537
29573
  init_Icon();
29538
29574
  init_cn();
29575
+ init_GameIcon();
29539
29576
  DEFAULT_ASSET_URL6 = {
29540
29577
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
29541
29578
  role: "ui",
@@ -29584,14 +29621,15 @@ function TimerDisplay({
29584
29621
  format = "mm:ss",
29585
29622
  size = "md",
29586
29623
  className,
29587
- lowThreshold
29624
+ lowThreshold,
29625
+ iconAsset
29588
29626
  }) {
29589
29627
  const isLow = lowThreshold != null && seconds <= lowThreshold && seconds > 0;
29590
- return /* @__PURE__ */ jsx(
29591
- "div",
29628
+ return /* @__PURE__ */ jsxs(
29629
+ Box,
29592
29630
  {
29593
29631
  className: cn(
29594
- "inline-flex items-center justify-center rounded-container",
29632
+ "inline-flex items-center gap-1 justify-center rounded-container",
29595
29633
  "bg-card/80 border border-muted font-mono font-bold tabular-nums",
29596
29634
  sizeMap9[size],
29597
29635
  running && "border-success/50",
@@ -29599,7 +29637,10 @@ function TimerDisplay({
29599
29637
  !isLow && "text-foreground",
29600
29638
  className
29601
29639
  ),
29602
- children: formatTime(seconds, format)
29640
+ children: [
29641
+ iconAsset && /* @__PURE__ */ jsx(GameIcon, { assetUrl: iconAsset, icon: "image", size: 16, className: "w-4 h-4 object-contain flex-shrink-0" }),
29642
+ formatTime(seconds, format)
29643
+ ]
29603
29644
  }
29604
29645
  );
29605
29646
  }
@@ -29607,6 +29648,8 @@ var sizeMap9;
29607
29648
  var init_TimerDisplay = __esm({
29608
29649
  "components/game/2d/atoms/TimerDisplay.tsx"() {
29609
29650
  init_cn();
29651
+ init_Box();
29652
+ init_GameIcon();
29610
29653
  sizeMap9 = {
29611
29654
  sm: "text-sm px-2 py-0.5",
29612
29655
  md: "text-lg px-3 py-1",
@@ -29627,7 +29670,7 @@ function ResourceCounter({
29627
29670
  }) {
29628
29671
  const sizes = sizeMap10[size];
29629
29672
  return /* @__PURE__ */ jsxs(
29630
- "div",
29673
+ Box,
29631
29674
  {
29632
29675
  className: cn(
29633
29676
  "inline-flex items-center rounded-container",
@@ -29636,21 +29679,11 @@ function ResourceCounter({
29636
29679
  className
29637
29680
  ),
29638
29681
  children: [
29639
- assetUrl ? /* @__PURE__ */ jsx(
29640
- "img",
29641
- {
29642
- src: assetUrl.url,
29643
- alt: label,
29644
- width: sizes.img,
29645
- height: sizes.img,
29646
- style: { imageRendering: "pixelated", objectFit: "contain" },
29647
- className: "flex-shrink-0"
29648
- }
29649
- ) : icon ? /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
29650
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
29651
- /* @__PURE__ */ jsxs("span", { className: cn("font-bold tabular-nums", color && (color in colorTokenClasses2 ? colorTokenClasses2[color] : color)), children: [
29682
+ assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: sizes.img, alt: label, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
29683
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground", children: label }),
29684
+ /* @__PURE__ */ jsxs(Typography, { as: "span", className: cn("font-bold tabular-nums", color && (color in colorTokenClasses2 ? colorTokenClasses2[color] : color)), children: [
29652
29685
  value,
29653
- max != null && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
29686
+ max != null && /* @__PURE__ */ jsxs(Typography, { as: "span", className: "text-muted-foreground", children: [
29654
29687
  "/",
29655
29688
  max
29656
29689
  ] })
@@ -29664,6 +29697,9 @@ var init_ResourceCounter = __esm({
29664
29697
  "components/game/2d/atoms/ResourceCounter.tsx"() {
29665
29698
  init_cn();
29666
29699
  init_Icon();
29700
+ init_Box();
29701
+ init_Typography();
29702
+ init_GameIcon();
29667
29703
  colorTokenClasses2 = {
29668
29704
  primary: "text-primary",
29669
29705
  secondary: "text-secondary",
@@ -29695,15 +29731,20 @@ function ItemSlot({
29695
29731
  size = "md",
29696
29732
  selected,
29697
29733
  onClick,
29734
+ action,
29698
29735
  className
29699
29736
  }) {
29700
- const isClickable = onClick != null;
29737
+ const eventBus = useEventBus();
29738
+ const isClickable = onClick != null || action != null;
29701
29739
  const px = assetSizeMap[size];
29702
29740
  return /* @__PURE__ */ jsx(
29703
- "button",
29741
+ Button,
29704
29742
  {
29705
- type: "button",
29706
- onClick,
29743
+ variant: "ghost",
29744
+ onClick: () => {
29745
+ if (action) eventBus.emit(`UI:${action}`, {});
29746
+ onClick?.();
29747
+ },
29707
29748
  disabled: !isClickable,
29708
29749
  title: label,
29709
29750
  className: cn(
@@ -29718,21 +29759,12 @@ function ItemSlot({
29718
29759
  !isClickable && "cursor-default",
29719
29760
  className
29720
29761
  ),
29721
- children: empty ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-base", children: "+" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
29722
- assetUrl ? /* @__PURE__ */ jsx(
29723
- "img",
29724
- {
29725
- src: assetUrl?.url,
29726
- alt: label,
29727
- width: px,
29728
- height: px,
29729
- style: { imageRendering: "pixelated", objectFit: "contain" },
29730
- className: "flex-shrink-0"
29731
- }
29732
- ) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
29762
+ children: empty ? /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground text-base", children: "+" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
29763
+ assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: px, alt: label, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
29733
29764
  quantity != null && quantity > 1 && /* @__PURE__ */ jsx(
29734
- "span",
29765
+ Typography,
29735
29766
  {
29767
+ as: "span",
29736
29768
  className: cn(
29737
29769
  "absolute -bottom-1 -right-1 flex items-center justify-center",
29738
29770
  "min-w-[18px] h-[18px] rounded-full px-1",
@@ -29751,6 +29783,11 @@ var init_ItemSlot = __esm({
29751
29783
  "use client";
29752
29784
  init_cn();
29753
29785
  init_Icon();
29786
+ init_useEventBus();
29787
+ init_Button();
29788
+ init_Box();
29789
+ init_Typography();
29790
+ init_GameIcon();
29754
29791
  sizeMap11 = {
29755
29792
  sm: "w-10 h-10 text-lg",
29756
29793
  md: "w-14 h-14 text-2xl",
@@ -29794,7 +29831,7 @@ function TurnIndicator({
29794
29831
  }) {
29795
29832
  const sizes = sizeMap12[size];
29796
29833
  return /* @__PURE__ */ jsxs(
29797
- "div",
29834
+ Box,
29798
29835
  {
29799
29836
  className: cn(
29800
29837
  "inline-flex items-center rounded-container",
@@ -29803,32 +29840,22 @@ function TurnIndicator({
29803
29840
  className
29804
29841
  ),
29805
29842
  children: [
29806
- /* @__PURE__ */ jsxs("span", { className: "font-bold tabular-nums", children: [
29843
+ /* @__PURE__ */ jsxs(Typography, { as: "span", className: "font-bold tabular-nums", children: [
29807
29844
  "Turn ",
29808
29845
  currentTurn,
29809
- maxTurns != null && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
29846
+ maxTurns != null && /* @__PURE__ */ jsxs(Typography, { as: "span", className: "text-muted-foreground", children: [
29810
29847
  "/",
29811
29848
  maxTurns
29812
29849
  ] })
29813
29850
  ] }),
29814
29851
  phase && /* @__PURE__ */ jsxs(Fragment, { children: [
29815
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "|" }),
29816
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: phase })
29852
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground", children: "|" }),
29853
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground", children: phase })
29817
29854
  ] }),
29818
29855
  activeTeam && /* @__PURE__ */ jsxs(Fragment, { children: [
29819
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "|" }),
29820
- assetUrl ? /* @__PURE__ */ jsx(
29821
- "img",
29822
- {
29823
- src: assetUrl.url,
29824
- alt: "",
29825
- width: 12,
29826
- height: 12,
29827
- style: { imageRendering: "pixelated", objectFit: "contain" },
29828
- className: "flex-shrink-0"
29829
- }
29830
- ) : /* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
29831
- /* @__PURE__ */ jsx("span", { className: "text-success", children: activeTeam })
29856
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground", children: "|" }),
29857
+ assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: 12, className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(Box, { as: "span", className: cn("rounded-full bg-success/20", sizes.dot) }),
29858
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-success", children: activeTeam })
29832
29859
  ] })
29833
29860
  ]
29834
29861
  }
@@ -29838,6 +29865,9 @@ var sizeMap12, DEFAULT_ASSET_URL9;
29838
29865
  var init_TurnIndicator = __esm({
29839
29866
  "components/game/2d/atoms/TurnIndicator.tsx"() {
29840
29867
  init_cn();
29868
+ init_Box();
29869
+ init_Typography();
29870
+ init_GameIcon();
29841
29871
  sizeMap12 = {
29842
29872
  sm: { wrapper: "text-xs gap-1.5 px-2 py-0.5", dot: "w-1.5 h-1.5" },
29843
29873
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
@@ -29861,53 +29891,47 @@ function WaypointMarker({
29861
29891
  className
29862
29892
  }) {
29863
29893
  const sizes = sizeMap13[size];
29864
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-center", className), children: [
29865
- /* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
29894
+ return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col items-center", className), children: [
29895
+ /* @__PURE__ */ jsxs(Box, { className: "relative flex items-center justify-center", children: [
29866
29896
  active && /* @__PURE__ */ jsx(
29867
- "div",
29897
+ Box,
29868
29898
  {
29899
+ position: "absolute",
29869
29900
  className: cn(
29870
- "absolute rounded-full border-2 border-info animate-ping opacity-50",
29901
+ "rounded-full border-2 border-info animate-ping opacity-50",
29871
29902
  sizes.ring
29872
29903
  )
29873
29904
  }
29874
29905
  ),
29875
29906
  active && /* @__PURE__ */ jsx(
29876
- "div",
29907
+ Box,
29877
29908
  {
29909
+ position: "absolute",
29878
29910
  className: cn(
29879
- "absolute rounded-full border-2 border-info",
29911
+ "rounded-full border-2 border-info",
29880
29912
  sizes.ring
29881
29913
  )
29882
29914
  }
29883
29915
  ),
29884
29916
  /* @__PURE__ */ jsx(
29885
- "div",
29917
+ Box,
29886
29918
  {
29919
+ position: "relative",
29887
29920
  className: cn(
29888
- "relative flex items-center justify-center rounded-full transition-all duration-200",
29921
+ "flex items-center justify-center rounded-full transition-all duration-200",
29889
29922
  sizes.dot,
29890
29923
  completed && "bg-success text-foreground",
29891
29924
  active && !completed && "bg-info text-foreground",
29892
29925
  !active && !completed && "bg-muted"
29893
29926
  ),
29894
- children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(
29895
- "img",
29896
- {
29897
- src: assetUrl.url,
29898
- alt: label,
29899
- width: sizes.img,
29900
- height: sizes.img,
29901
- style: { imageRendering: "pixelated", objectFit: "contain" },
29902
- className: "flex-shrink-0"
29903
- }
29904
- ) : icon ? typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) : null
29927
+ children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: sizes.img, alt: label, className: "flex-shrink-0" }) : icon ? typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) : null
29905
29928
  }
29906
29929
  )
29907
29930
  ] }),
29908
29931
  label && /* @__PURE__ */ jsx(
29909
- "span",
29932
+ Typography,
29910
29933
  {
29934
+ as: "span",
29911
29935
  className: cn(
29912
29936
  "text-center whitespace-nowrap",
29913
29937
  sizes.label,
@@ -29923,6 +29947,9 @@ var init_WaypointMarker = __esm({
29923
29947
  "components/game/2d/atoms/WaypointMarker.tsx"() {
29924
29948
  init_cn();
29925
29949
  init_Icon();
29950
+ init_Box();
29951
+ init_Typography();
29952
+ init_GameIcon();
29926
29953
  DEFAULT_ASSET_URL10 = {
29927
29954
  url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
29928
29955
  role: "ui",
@@ -29954,31 +29981,23 @@ function StatusEffect({
29954
29981
  className
29955
29982
  }) {
29956
29983
  const sizes = sizeMap14[size];
29957
- return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex flex-col items-center", className), children: [
29984
+ return /* @__PURE__ */ jsxs(Box, { position: "relative", className: cn("inline-flex flex-col items-center", className), children: [
29958
29985
  /* @__PURE__ */ jsxs(
29959
- "div",
29986
+ Box,
29960
29987
  {
29988
+ position: "relative",
29961
29989
  className: cn(
29962
- "relative flex items-center justify-center rounded-interactive border-2",
29990
+ "flex items-center justify-center rounded-interactive border-2",
29963
29991
  sizes.container,
29964
29992
  variantStyles8[variant]
29965
29993
  ),
29966
29994
  title: label,
29967
29995
  children: [
29968
- /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(
29969
- "img",
29970
- {
29971
- src: assetUrl.url,
29972
- alt: label,
29973
- width: sizes.img,
29974
- height: sizes.img,
29975
- style: { imageRendering: "pixelated", objectFit: "contain" },
29976
- className: "flex-shrink-0"
29977
- }
29978
- ) : icon != null && typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, size: "sm" }) : icon != null ? /* @__PURE__ */ jsx(Icon, { icon, size: "sm" }) : null }),
29996
+ /* @__PURE__ */ jsx(Box, { as: "span", className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(GameIcon, { assetUrl, icon: "image", size: sizes.img, alt: label, className: "flex-shrink-0" }) : icon != null && typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, size: "sm" }) : icon != null ? /* @__PURE__ */ jsx(Icon, { icon, size: "sm" }) : null }),
29979
29997
  duration !== void 0 && /* @__PURE__ */ jsx(
29980
- "span",
29998
+ Typography,
29981
29999
  {
30000
+ as: "span",
29982
30001
  className: cn(
29983
30002
  "absolute bottom-0 left-0 right-0 text-center font-mono font-bold text-foreground bg-background/60 leading-tight",
29984
30003
  sizes.timer
@@ -29990,8 +30009,9 @@ function StatusEffect({
29990
30009
  }
29991
30010
  ),
29992
30011
  stacks !== void 0 && stacks > 1 && /* @__PURE__ */ jsx(
29993
- "span",
30012
+ Typography,
29994
30013
  {
30014
+ as: "span",
29995
30015
  className: cn(
29996
30016
  "absolute flex items-center justify-center rounded-full bg-card text-foreground font-bold leading-none",
29997
30017
  sizes.badge
@@ -29999,7 +30019,7 @@ function StatusEffect({
29999
30019
  children: stacks
30000
30020
  }
30001
30021
  ),
30002
- label && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
30022
+ label && /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
30003
30023
  ] });
30004
30024
  }
30005
30025
  var DEFAULT_ASSET_URL11, sizeMap14, variantStyles8;
@@ -30007,6 +30027,9 @@ var init_StatusEffect = __esm({
30007
30027
  "components/game/2d/atoms/StatusEffect.tsx"() {
30008
30028
  init_cn();
30009
30029
  init_Icon();
30030
+ init_Box();
30031
+ init_Typography();
30032
+ init_GameIcon();
30010
30033
  DEFAULT_ASSET_URL11 = {
30011
30034
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
30012
30035
  role: "ui",
@@ -30033,7 +30056,7 @@ function DialogueBubble({
30033
30056
  className
30034
30057
  }) {
30035
30058
  return /* @__PURE__ */ jsxs(
30036
- "div",
30059
+ Box,
30037
30060
  {
30038
30061
  className: cn(
30039
30062
  "flex items-start gap-3 rounded-container bg-background/80 backdrop-blur-sm px-4 py-3 border border-border/10",
@@ -30041,17 +30064,10 @@ function DialogueBubble({
30041
30064
  className
30042
30065
  ),
30043
30066
  children: [
30044
- portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(
30045
- "img",
30046
- {
30047
- src: portrait?.url,
30048
- alt: speaker ?? "speaker",
30049
- className: "w-full h-full object-cover"
30050
- }
30051
- ) }),
30052
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 min-w-0", children: [
30053
- speaker && /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-warning", children: speaker }),
30054
- /* @__PURE__ */ jsx("span", { className: "text-sm text-foreground leading-relaxed", children: text })
30067
+ portrait && /* @__PURE__ */ jsx(Box, { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(GameIcon, { assetUrl: portrait, icon: "image", size: 48, alt: speaker ?? "speaker", className: "w-full h-full object-cover" }) }),
30068
+ /* @__PURE__ */ jsxs(Box, { className: "flex flex-col gap-1 min-w-0", children: [
30069
+ speaker && /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-sm font-bold text-warning", children: speaker }),
30070
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-sm text-foreground leading-relaxed", children: text })
30055
30071
  ] })
30056
30072
  ]
30057
30073
  }
@@ -30061,6 +30077,9 @@ var DEFAULT_PORTRAIT;
30061
30077
  var init_DialogueBubble = __esm({
30062
30078
  "components/game/2d/atoms/DialogueBubble.tsx"() {
30063
30079
  init_cn();
30080
+ init_Box();
30081
+ init_Typography();
30082
+ init_GameIcon();
30064
30083
  DEFAULT_PORTRAIT = {
30065
30084
  url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
30066
30085
  role: "effect",
@@ -30087,7 +30106,7 @@ function StatBadge({
30087
30106
  const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
30088
30107
  const resolvedAsset = iconUrl ?? assetUrl;
30089
30108
  return /* @__PURE__ */ jsxs(
30090
- "div",
30109
+ Box,
30091
30110
  {
30092
30111
  className: cn(
30093
30112
  "inline-flex items-center gap-2 rounded-container border backdrop-blur-sm",
@@ -30096,18 +30115,8 @@ function StatBadge({
30096
30115
  className
30097
30116
  ),
30098
30117
  children: [
30099
- resolvedAsset ? /* @__PURE__ */ jsx(
30100
- "img",
30101
- {
30102
- src: resolvedAsset.url,
30103
- alt: "",
30104
- width: 16,
30105
- height: 16,
30106
- style: { imageRendering: "pixelated", objectFit: "contain" },
30107
- className: "flex-shrink-0"
30108
- }
30109
- ) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
30110
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-medium", children: label }),
30118
+ resolvedAsset ? /* @__PURE__ */ jsx(GameIcon, { assetUrl: resolvedAsset, icon: "image", size: 16, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
30119
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground font-medium", children: label }),
30111
30120
  format === "hearts" && max && /* @__PURE__ */ jsx(
30112
30121
  HealthBar,
30113
30122
  {
@@ -30133,7 +30142,7 @@ function StatBadge({
30133
30142
  size: size === "lg" ? "md" : "sm"
30134
30143
  }
30135
30144
  ),
30136
- format === "text" && /* @__PURE__ */ jsx("span", { className: "font-bold text-foreground", children: value })
30145
+ format === "text" && /* @__PURE__ */ jsx(Typography, { as: "span", className: "font-bold text-foreground", children: value })
30137
30146
  ]
30138
30147
  }
30139
30148
  );
@@ -30143,6 +30152,9 @@ var init_StatBadge = __esm({
30143
30152
  "components/game/2d/molecules/StatBadge.tsx"() {
30144
30153
  init_cn();
30145
30154
  init_Icon();
30155
+ init_Box();
30156
+ init_Typography();
30157
+ init_GameIcon();
30146
30158
  init_HealthBar();
30147
30159
  init_ScoreDisplay();
30148
30160
  sizeMap15 = {
@@ -30177,7 +30189,7 @@ function InventoryGrid({
30177
30189
  (id) => {
30178
30190
  onSelect?.(id);
30179
30191
  if (selectEvent) {
30180
- eventBus.emit(selectEvent, { id });
30192
+ eventBus.emit(`UI:${selectEvent}`, { id });
30181
30193
  }
30182
30194
  },
30183
30195
  [onSelect, selectEvent, eventBus]
@@ -30320,9 +30332,9 @@ function GameHud({
30320
30332
  if (position === "corners") {
30321
30333
  const leftStats = stats.slice(0, Math.ceil(stats.length / 2));
30322
30334
  const rightStats = stats.slice(Math.ceil(stats.length / 2));
30323
- return /* @__PURE__ */ jsxs("div", { className: cn("relative", positionMap[position], className), children: [
30324
- /* @__PURE__ */ jsx("div", { className: "absolute top-4 left-4 flex flex-col gap-2 pointer-events-auto", children: leftStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) }),
30325
- /* @__PURE__ */ jsx("div", { className: "absolute top-4 right-4 flex flex-col gap-2 items-end pointer-events-auto", children: rightStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) })
30335
+ return /* @__PURE__ */ jsxs(Box, { position: "relative", className: cn(positionMap[position], className), children: [
30336
+ /* @__PURE__ */ jsx(Box, { position: "absolute", className: "top-4 left-4 flex flex-col gap-2 pointer-events-auto", children: leftStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) }),
30337
+ /* @__PURE__ */ jsx(Box, { position: "absolute", className: "top-4 right-4 flex flex-col gap-2 items-end pointer-events-auto", children: rightStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) })
30326
30338
  ] });
30327
30339
  }
30328
30340
  if (position === "top" || position === "bottom") {
@@ -30331,7 +30343,7 @@ function GameHud({
30331
30343
  const rightStats = stats.slice(mid);
30332
30344
  const isTop = position === "top";
30333
30345
  return /* @__PURE__ */ jsxs(
30334
- "div",
30346
+ Box,
30335
30347
  {
30336
30348
  className: cn(
30337
30349
  "flex items-center justify-between w-full",
@@ -30341,17 +30353,18 @@ function GameHud({
30341
30353
  className
30342
30354
  ),
30343
30355
  children: [
30344
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 flex-shrink-0", children: leftStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) }),
30345
- rightStats.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 flex-shrink-0", children: rightStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) })
30356
+ /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-3 flex-shrink-0", children: leftStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) }),
30357
+ rightStats.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-3 flex-shrink-0", children: rightStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) })
30346
30358
  ]
30347
30359
  }
30348
30360
  );
30349
30361
  }
30350
30362
  return /* @__PURE__ */ jsx(
30351
- "div",
30363
+ Box,
30352
30364
  {
30365
+ position: "relative",
30353
30366
  className: cn(
30354
- "relative z-10 flex items-center gap-4 px-4 py-2",
30367
+ "z-10 flex items-center gap-4 px-4 py-2",
30355
30368
  transparent ? "bg-black/30 backdrop-blur-sm" : "bg-surface/90 backdrop-blur-sm",
30356
30369
  className
30357
30370
  ),
@@ -30363,6 +30376,7 @@ var positionMap, DEFAULT_HUD_STATS;
30363
30376
  var init_GameHud = __esm({
30364
30377
  "components/game/2d/molecules/GameHud.tsx"() {
30365
30378
  init_cn();
30379
+ init_Box();
30366
30380
  init_StatBadge();
30367
30381
  positionMap = {
30368
30382
  corners: "inset-0 pointer-events-none"
@@ -30382,34 +30396,28 @@ function GameMenu({
30382
30396
  options,
30383
30397
  menuItems,
30384
30398
  onSelect,
30385
- eventBus: eventBusProp,
30386
30399
  background,
30387
- logo = "",
30400
+ logo,
30388
30401
  className
30389
30402
  }) {
30390
30403
  const resolvedOptions = options ?? menuItems ?? DEFAULT_MENU_OPTIONS;
30391
- let eventBusFromHook = null;
30392
- try {
30393
- eventBusFromHook = useEventBus();
30394
- } catch {
30395
- }
30396
- const eventBus = eventBusProp || eventBusFromHook;
30404
+ const eventBus = useEventBus();
30397
30405
  const handleOptionClick = React79.useCallback(
30398
30406
  (option) => {
30399
- if (option.event && eventBus) {
30407
+ if (option.event) {
30400
30408
  eventBus.emit(`UI:${option.event}`, { option });
30401
30409
  }
30402
30410
  if (onSelect) {
30403
30411
  onSelect(option);
30404
30412
  }
30405
- if (option.navigatesTo && eventBus) {
30413
+ if (option.navigatesTo) {
30406
30414
  eventBus.emit("UI:NAVIGATE", { url: option.navigatesTo, option });
30407
30415
  }
30408
30416
  },
30409
30417
  [eventBus, onSelect]
30410
30418
  );
30411
30419
  return /* @__PURE__ */ jsxs(
30412
- "div",
30420
+ Box,
30413
30421
  {
30414
30422
  className: cn(
30415
30423
  "min-h-screen w-full flex flex-col items-center justify-center p-8",
@@ -30419,18 +30427,12 @@ function GameMenu({
30419
30427
  background: background ?? "linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f0e17 100%)"
30420
30428
  },
30421
30429
  children: [
30422
- /* @__PURE__ */ jsxs("div", { className: "text-center mb-12 animate-fade-in", children: [
30423
- logo && /* @__PURE__ */ jsx(
30424
- "img",
30425
- {
30426
- src: logo,
30427
- alt: title,
30428
- className: "h-24 w-auto mx-auto mb-6 drop-shadow-2xl"
30429
- }
30430
- ),
30430
+ /* @__PURE__ */ jsxs(Box, { className: "text-center mb-12 animate-fade-in", children: [
30431
+ logo && /* @__PURE__ */ jsx(GameIcon, { assetUrl: logo, icon: "image", size: 96, alt: title, className: "h-24 w-auto mx-auto mb-6 drop-shadow-2xl" }),
30431
30432
  /* @__PURE__ */ jsx(
30432
- "h1",
30433
+ Typography,
30433
30434
  {
30435
+ variant: "h1",
30434
30436
  className: "text-5xl md:text-7xl font-bold text-[var(--color-foreground)] tracking-tight",
30435
30437
  style: {
30436
30438
  textShadow: "0 4px 12px rgba(0,0,0,0.5)"
@@ -30438,9 +30440,9 @@ function GameMenu({
30438
30440
  children: title
30439
30441
  }
30440
30442
  ),
30441
- subtitle && /* @__PURE__ */ jsx("p", { className: "mt-2 text-lg text-muted-foreground tracking-widest uppercase", children: subtitle })
30443
+ subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", className: "mt-2 text-lg text-muted-foreground tracking-widest uppercase", children: subtitle })
30442
30444
  ] }),
30443
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 w-full max-w-md", children: resolvedOptions.map((option, index) => /* @__PURE__ */ jsx(
30445
+ /* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-4 w-full max-w-md", children: resolvedOptions.map((option, index) => /* @__PURE__ */ jsx(
30444
30446
  ChoiceButton,
30445
30447
  {
30446
30448
  text: option.label,
@@ -30451,9 +30453,9 @@ function GameMenu({
30451
30453
  },
30452
30454
  index
30453
30455
  )) }),
30454
- /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 pointer-events-none overflow-hidden", children: [
30455
- /* @__PURE__ */ jsx("div", { className: "absolute top-1/4 left-1/4 w-64 h-64 bg-info/10 rounded-container blur-3xl" }),
30456
- /* @__PURE__ */ jsx("div", { className: "absolute bottom-1/4 right-1/4 w-96 h-96 bg-accent/10 rounded-container blur-3xl" })
30456
+ /* @__PURE__ */ jsxs(Box, { position: "absolute", className: "inset-0 pointer-events-none overflow-hidden", children: [
30457
+ /* @__PURE__ */ jsx(Box, { position: "absolute", className: "top-1/4 left-1/4 w-64 h-64 bg-info/10 rounded-container blur-3xl" }),
30458
+ /* @__PURE__ */ jsx(Box, { position: "absolute", className: "bottom-1/4 right-1/4 w-96 h-96 bg-accent/10 rounded-container blur-3xl" })
30457
30459
  ] })
30458
30460
  ]
30459
30461
  }
@@ -30465,6 +30467,9 @@ var init_GameMenu = __esm({
30465
30467
  "use client";
30466
30468
  init_cn();
30467
30469
  init_useEventBus();
30470
+ init_Box();
30471
+ init_Typography();
30472
+ init_GameIcon();
30468
30473
  init_ChoiceButton();
30469
30474
  DEFAULT_MENU_OPTIONS = [
30470
30475
  { label: "New Game", event: "NEW_GAME", variant: "primary" },
@@ -30883,7 +30888,9 @@ var init_GameAudioProvider = __esm({
30883
30888
  });
30884
30889
  function GameAudioToggle({
30885
30890
  size = "sm",
30886
- className
30891
+ className,
30892
+ onAsset,
30893
+ offAsset
30887
30894
  }) {
30888
30895
  const ctx = useGameAudioContextOptional();
30889
30896
  const [localMuted, setLocalMuted] = useState(false);
@@ -30892,6 +30899,7 @@ function GameAudioToggle({
30892
30899
  const handleToggle = useCallback(() => {
30893
30900
  setMuted(!muted);
30894
30901
  }, [muted, setMuted]);
30902
+ const activeAsset = muted ? offAsset : onAsset;
30895
30903
  return /* @__PURE__ */ jsx(
30896
30904
  Button,
30897
30905
  {
@@ -30900,7 +30908,7 @@ function GameAudioToggle({
30900
30908
  onClick: handleToggle,
30901
30909
  className: cn("text-lg leading-none px-2", className),
30902
30910
  "aria-pressed": muted,
30903
- children: muted ? "\u{1F507}" : "\u{1F50A}"
30911
+ children: activeAsset ? /* @__PURE__ */ 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}"
30904
30912
  }
30905
30913
  );
30906
30914
  }
@@ -30910,6 +30918,7 @@ var init_GameAudioToggle = __esm({
30910
30918
  init_atoms();
30911
30919
  init_cn();
30912
30920
  init_GameAudioProvider();
30921
+ init_GameIcon();
30913
30922
  GameAudioToggle.displayName = "GameAudioToggle";
30914
30923
  }
30915
30924
  });
@@ -31489,6 +31498,7 @@ function PlatformerBoard({
31489
31498
  canvasHeight: _canvasHeight = 400,
31490
31499
  playerSprite,
31491
31500
  tileSprites,
31501
+ ui: _ui,
31492
31502
  bgColor: _bgColor,
31493
31503
  keyEvent = "KEY",
31494
31504
  playAgainEvent = "PLAY_AGAIN",
@@ -32913,6 +32923,7 @@ function TanksBoard({
32913
32923
  features,
32914
32924
  assetManifest,
32915
32925
  assetBaseUrl,
32926
+ ui: _ui,
32916
32927
  scale = 0.45,
32917
32928
  showMinimap = true,
32918
32929
  enableCamera = true,
@@ -33620,7 +33631,7 @@ function TraitSlot({
33620
33631
  size = "md",
33621
33632
  showTooltip = true,
33622
33633
  categoryColors,
33623
- tooltipFrameUrl = "",
33634
+ tooltipFrameUrl,
33624
33635
  className,
33625
33636
  feedback,
33626
33637
  onItemDrop,
@@ -33750,7 +33761,7 @@ function TraitSlot({
33750
33761
  as: "img",
33751
33762
  className: "object-contain",
33752
33763
  style: { width: config.icon, height: config.icon },
33753
- ...{ src: equippedItem.iconUrl, alt: equippedItem.name }
33764
+ ...{ src: equippedItem.iconUrl.url, alt: equippedItem.name }
33754
33765
  }
33755
33766
  ) : /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-center leading-none", style: { fontSize: config.icon }, children: equippedItem.iconEmoji || "\u2726" }),
33756
33767
  (onRemove || removeEvent) && /* @__PURE__ */ jsx(
@@ -33779,7 +33790,7 @@ function TraitSlot({
33779
33790
  ...getTooltipStyle(),
33780
33791
  minWidth: 200,
33781
33792
  ...tooltipFrameUrl ? {
33782
- borderImage: `url(${tooltipFrameUrl}) 60 fill / 15px / 0 stretch`,
33793
+ borderImage: `url(${tooltipFrameUrl.url}) 60 fill / 15px / 0 stretch`,
33783
33794
  border: "none"
33784
33795
  } : {}
33785
33796
  },
@@ -34076,6 +34087,42 @@ function computeSlotFeedback(playerSeq, solutions) {
34076
34087
  (id, i) => id !== void 0 && id === bestSolution[i] ? "correct" : "wrong"
34077
34088
  );
34078
34089
  }
34090
+ function isFieldRecord(v) {
34091
+ return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Date);
34092
+ }
34093
+ function assetFromField(v) {
34094
+ if (!isFieldRecord(v)) return void 0;
34095
+ const url = typeof v.url === "string" ? v.url : void 0;
34096
+ const role = typeof v.role === "string" ? v.role : void 0;
34097
+ const category = typeof v.category === "string" ? v.category : "";
34098
+ if (!url || !role) return void 0;
34099
+ return {
34100
+ url,
34101
+ role,
34102
+ category,
34103
+ name: typeof v.name === "string" ? v.name : void 0,
34104
+ thumbnailUrl: typeof v.thumbnailUrl === "string" ? v.thumbnailUrl : void 0,
34105
+ style: typeof v.style === "string" ? v.style : void 0,
34106
+ variant: typeof v.variant === "string" ? v.variant : void 0,
34107
+ dimension: typeof v.dimension === "string" ? v.dimension : void 0,
34108
+ aspect: typeof v.aspect === "string" ? v.aspect : void 0
34109
+ };
34110
+ }
34111
+ function slotItemFromField(fv) {
34112
+ if (!isFieldRecord(fv)) return void 0;
34113
+ const id = typeof fv.id === "string" ? fv.id : void 0;
34114
+ const name = typeof fv.name === "string" ? fv.name : void 0;
34115
+ const category = typeof fv.category === "string" ? fv.category : void 0;
34116
+ if (!id || !name || !category) return void 0;
34117
+ return {
34118
+ id,
34119
+ name,
34120
+ category,
34121
+ description: typeof fv.description === "string" ? fv.description : void 0,
34122
+ iconEmoji: typeof fv.iconEmoji === "string" ? fv.iconEmoji : void 0,
34123
+ iconUrl: assetFromField(fv.iconUrl)
34124
+ };
34125
+ }
34079
34126
  function SequencerBoard({
34080
34127
  entity,
34081
34128
  categoryColors,
@@ -34086,6 +34133,7 @@ function SequencerBoard({
34086
34133
  removeEvent,
34087
34134
  checkEvent,
34088
34135
  playAgainEvent,
34136
+ stepEvent,
34089
34137
  className
34090
34138
  }) {
34091
34139
  const { emit } = useEventBus();
@@ -34093,7 +34141,11 @@ function SequencerBoard({
34093
34141
  const resolved = boardEntity(entity);
34094
34142
  const maxSlots = num(resolved?.maxSlots) || 3;
34095
34143
  const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
34096
- const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
34144
+ const availableActions = (Array.isArray(resolved?.availableActions) ? resolved.availableActions : []).reduce((acc, fv) => {
34145
+ const item = slotItemFromField(fv);
34146
+ if (item) acc.push(item);
34147
+ return acc;
34148
+ }, []);
34097
34149
  const allowDuplicates = resolved?.allowDuplicates !== false;
34098
34150
  const entitySlots = Array.isArray(resolved?.slots) ? resolved.slots : [];
34099
34151
  const entityResult = str(resolved?.result);
@@ -34151,7 +34203,7 @@ function SequencerBoard({
34151
34203
  let step = 0;
34152
34204
  const advance = () => {
34153
34205
  step++;
34154
- emit("UI:STEP", { step });
34206
+ if (stepEvent) emit(`UI:${stepEvent}`, { step });
34155
34207
  if (step >= maxSlots) {
34156
34208
  if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
34157
34209
  const playerSeq = slots.map((s) => s?.id);
@@ -36050,24 +36102,55 @@ function SimulationControls({
36050
36102
  onReset,
36051
36103
  onSpeedChange,
36052
36104
  onParameterChange,
36105
+ playEvent,
36106
+ pauseEvent,
36107
+ stepEvent,
36108
+ resetEvent,
36109
+ speedChangeEvent,
36110
+ parameterChangeEvent,
36053
36111
  assetManifest,
36054
36112
  className
36055
36113
  }) {
36114
+ const eventBus = useEventBus();
36056
36115
  const ui = assetManifest?.ui;
36116
+ const handlePlay = () => {
36117
+ if (playEvent) eventBus.emit(`UI:${playEvent}`, {});
36118
+ onPlay?.();
36119
+ };
36120
+ const handlePause = () => {
36121
+ if (pauseEvent) eventBus.emit(`UI:${pauseEvent}`, {});
36122
+ onPause?.();
36123
+ };
36124
+ const handleStep = () => {
36125
+ if (stepEvent) eventBus.emit(`UI:${stepEvent}`, {});
36126
+ onStep?.();
36127
+ };
36128
+ const handleReset = () => {
36129
+ if (resetEvent) eventBus.emit(`UI:${resetEvent}`, {});
36130
+ onReset?.();
36131
+ };
36132
+ const handleSpeedChange = (s) => {
36133
+ if (speedChangeEvent) eventBus.emit(`UI:${speedChangeEvent}`, { speed: s });
36134
+ onSpeedChange?.(s);
36135
+ };
36136
+ const handleParameterChange = (name, value) => {
36137
+ if (parameterChangeEvent) eventBus.emit(`UI:${parameterChangeEvent}`, { name, value });
36138
+ onParameterChange?.(name, value);
36139
+ };
36057
36140
  return /* @__PURE__ */ jsxs(VStack, { gap: "md", className, children: [
36058
36141
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", children: [
36059
- running ? /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "secondary", onClick: onPause, children: [
36142
+ running ? /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "secondary", onClick: handlePause, children: [
36060
36143
  /* @__PURE__ */ jsx(GameIcon, { icon: Pause, assetUrl: ui?.["pause"], size: "sm" }),
36061
36144
  "Pause"
36062
- ] }) : /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "primary", onClick: onPlay, children: [
36145
+ ] }) : /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "primary", onClick: handlePlay, children: [
36063
36146
  /* @__PURE__ */ jsx(GameIcon, { icon: Play, assetUrl: ui?.["play"], size: "sm" }),
36064
36147
  "Play"
36065
36148
  ] }),
36066
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: onStep, disabled: running, children: [
36149
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: handleStep, disabled: running, children: [
36067
36150
  /* @__PURE__ */ jsx(GameIcon, { icon: SkipForward, assetUrl: ui?.["step"], size: "sm" }),
36068
36151
  "Step"
36069
36152
  ] }),
36070
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: onReset, children: [
36153
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: handleReset, children: [
36071
36154
  /* @__PURE__ */ jsx(GameIcon, { icon: RotateCcw, assetUrl: ui?.["reset"], size: "sm" }),
36072
36155
  "Reset"
36073
36156
  ] })
@@ -36086,7 +36169,7 @@ function SimulationControls({
36086
36169
  max: 5,
36087
36170
  step: 0.1,
36088
36171
  value: speed,
36089
- onChange: (e) => onSpeedChange(parseFloat(e.target.value)),
36172
+ onChange: (e) => handleSpeedChange(parseFloat(e.target.value)),
36090
36173
  className: "w-full"
36091
36174
  }
36092
36175
  )
@@ -36105,7 +36188,7 @@ function SimulationControls({
36105
36188
  max: param.max,
36106
36189
  step: param.step,
36107
36190
  value: param.value,
36108
- onChange: (e) => onParameterChange(name, parseFloat(e.target.value)),
36191
+ onChange: (e) => handleParameterChange(name, parseFloat(e.target.value)),
36109
36192
  className: "w-full"
36110
36193
  }
36111
36194
  )
@@ -36114,6 +36197,7 @@ function SimulationControls({
36114
36197
  }
36115
36198
  var init_SimulationControls = __esm({
36116
36199
  "components/game/2d/organisms/SimulationControls.tsx"() {
36200
+ init_useEventBus();
36117
36201
  init_atoms();
36118
36202
  init_GameIcon();
36119
36203
  SimulationControls.displayName = "SimulationControls";
@@ -36182,35 +36266,7 @@ var init_SimulationGraph = __esm({
36182
36266
  SimulationGraph.displayName = "SimulationGraph";
36183
36267
  }
36184
36268
  });
36185
- function getSlotContentRenderer() {
36186
- if (_scr) return _scr;
36187
- const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
36188
- _scr = mod.SlotContentRenderer;
36189
- return _scr;
36190
- }
36191
- function resolveDescriptor(value, idPrefix) {
36192
- if (value === null || value === void 0) return value;
36193
- if (React79__default.isValidElement(value)) return value;
36194
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
36195
- if (Array.isArray(value)) {
36196
- return value.map((item, i) => /* @__PURE__ */ jsx(React79__default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
36197
- }
36198
- if (typeof value === "object") {
36199
- const rec = value;
36200
- if (typeof rec.type === "string" && getComponentForPattern(rec.type) !== null) {
36201
- const type = rec.type;
36202
- const _id = typeof rec._id === "string" ? rec._id : void 0;
36203
- const nestedProps = rec.props !== void 0 && typeof rec.props === "object" && !Array.isArray(rec.props) && rec.props !== null ? rec.props : void 0;
36204
- const { type: _t, props: _p, _id: _d, ...flatRest } = rec;
36205
- const resolvedProps = nestedProps !== void 0 ? nestedProps : flatRest;
36206
- const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
36207
- const SCR = getSlotContentRenderer();
36208
- return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
36209
- }
36210
- }
36211
- return null;
36212
- }
36213
- var _scr, GameTemplate;
36269
+ var GameTemplate;
36214
36270
  var init_GameTemplate = __esm({
36215
36271
  "components/game/2d/templates/GameTemplate.tsx"() {
36216
36272
  init_cn();
@@ -36218,7 +36274,6 @@ var init_GameTemplate = __esm({
36218
36274
  init_Stack();
36219
36275
  init_Typography();
36220
36276
  init_Button();
36221
- _scr = null;
36222
36277
  GameTemplate = ({
36223
36278
  entity,
36224
36279
  title = "Game",
@@ -36227,7 +36282,8 @@ var init_GameTemplate = __esm({
36227
36282
  debugPanel,
36228
36283
  showDebugPanel = false,
36229
36284
  controls,
36230
- className
36285
+ className,
36286
+ backgroundAsset
36231
36287
  }) => {
36232
36288
  return /* @__PURE__ */ jsxs(
36233
36289
  Box,
@@ -36284,15 +36340,16 @@ var init_GameTemplate = __esm({
36284
36340
  {
36285
36341
  position: "relative",
36286
36342
  fullWidth: true,
36287
- className: "flex-1 bg-muted",
36343
+ className: backgroundAsset ? "flex-1" : "flex-1 bg-muted",
36344
+ style: backgroundAsset ? { backgroundImage: `url(${backgroundAsset.url})`, backgroundSize: "cover", backgroundPosition: "center" } : void 0,
36288
36345
  children: [
36289
- resolveDescriptor(children, "gt-children"),
36346
+ children,
36290
36347
  hud && /* @__PURE__ */ jsx(
36291
36348
  Box,
36292
36349
  {
36293
36350
  position: "absolute",
36294
36351
  className: "top-0 left-0 right-0 pointer-events-none",
36295
- children: /* @__PURE__ */ jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: resolveDescriptor(hud, "gt-hud") })
36352
+ children: /* @__PURE__ */ jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
36296
36353
  }
36297
36354
  )
36298
36355
  ]
@@ -36317,7 +36374,7 @@ var init_GameTemplate = __esm({
36317
36374
  children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Debug Panel" })
36318
36375
  }
36319
36376
  ),
36320
- /* @__PURE__ */ jsx(Box, { padding: "md", children: resolveDescriptor(debugPanel, "gt-debug") })
36377
+ /* @__PURE__ */ jsx(Box, { padding: "md", children: debugPanel })
36321
36378
  ]
36322
36379
  }
36323
36380
  )
@@ -36328,59 +36385,21 @@ var init_GameTemplate = __esm({
36328
36385
  GameTemplate.displayName = "GameTemplate";
36329
36386
  }
36330
36387
  });
36331
- function asDescriptor(v) {
36332
- if (Array.isArray(v) || React79__default.isValidElement(v)) return null;
36333
- const o = v;
36334
- if (typeof o.type !== "string") return null;
36335
- const props = o.props !== void 0 && typeof o.props === "object" && !Array.isArray(o.props) && o.props !== null ? o.props : void 0;
36336
- const _id = typeof o._id === "string" ? o._id : void 0;
36337
- const sourceTrait = typeof o.sourceTrait === "string" ? o.sourceTrait : void 0;
36338
- return { type: o.type, props, _id, sourceTrait };
36339
- }
36340
- function getSlotContentRenderer2() {
36341
- if (_scr2) return _scr2;
36342
- const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
36343
- _scr2 = mod.SlotContentRenderer;
36344
- return _scr2;
36345
- }
36346
- function resolveDescriptor2(value, idPrefix) {
36347
- if (value === null || value === void 0) return value;
36348
- if (React79__default.isValidElement(value)) return value;
36349
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
36350
- if (Array.isArray(value)) {
36351
- return value.map((item, i) => /* @__PURE__ */ jsx(React79__default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
36352
- }
36353
- if (typeof value === "object" && value !== null) {
36354
- const desc = asDescriptor(value);
36355
- if (desc !== null && getComponentForPattern(desc.type) !== null) {
36356
- const resolvedProps = desc.props ?? {};
36357
- const content = {
36358
- id: desc._id ?? idPrefix,
36359
- pattern: desc.type,
36360
- props: resolvedProps,
36361
- priority: 0,
36362
- ...desc.sourceTrait !== void 0 && { sourceTrait: desc.sourceTrait }
36363
- };
36364
- const SCR = getSlotContentRenderer2();
36365
- return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
36366
- }
36367
- }
36368
- return null;
36369
- }
36370
- var _scr2, GameShell;
36388
+ var GameShell;
36371
36389
  var init_GameShell = __esm({
36372
36390
  "components/game/2d/templates/GameShell.tsx"() {
36373
36391
  init_cn();
36374
36392
  init_Box();
36375
36393
  init_Stack();
36376
36394
  init_Typography();
36377
- _scr2 = null;
36378
36395
  GameShell = ({
36379
36396
  appName = "Game",
36380
36397
  hud,
36381
36398
  className,
36382
36399
  showTopBar = true,
36383
- children
36400
+ children,
36401
+ backgroundAsset,
36402
+ hudBackgroundAsset
36384
36403
  }) => {
36385
36404
  return /* @__PURE__ */ jsxs(
36386
36405
  Box,
@@ -36395,7 +36414,7 @@ var init_GameShell = __esm({
36395
36414
  width: "100vw",
36396
36415
  height: "100vh",
36397
36416
  overflow: "hidden",
36398
- background: "var(--color-background, #0a0a0f)",
36417
+ background: backgroundAsset ? `url(${backgroundAsset.url}) center/cover no-repeat` : "var(--color-background, #0a0a0f)",
36399
36418
  color: "var(--color-text, #e0e0e0)"
36400
36419
  },
36401
36420
  children: [
@@ -36405,7 +36424,7 @@ var init_GameShell = __esm({
36405
36424
  className: "game-shell__header",
36406
36425
  style: {
36407
36426
  flexShrink: 0,
36408
- background: "var(--color-surface, #12121f)",
36427
+ background: hudBackgroundAsset ? `url(${hudBackgroundAsset.url}) center/cover no-repeat` : "var(--color-surface, #12121f)",
36409
36428
  borderBottom: "1px solid var(--color-border, #2a2a3a)"
36410
36429
  },
36411
36430
  children: [
@@ -36428,7 +36447,7 @@ var init_GameShell = __esm({
36428
36447
  )
36429
36448
  }
36430
36449
  ),
36431
- hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", style: { width: "100%" }, children: resolveDescriptor2(hud, "gs-hud") })
36450
+ hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", style: { width: "100%" }, children: hud })
36432
36451
  ]
36433
36452
  }
36434
36453
  ),
@@ -36441,7 +36460,7 @@ var init_GameShell = __esm({
36441
36460
  overflow: "hidden",
36442
36461
  position: "relative"
36443
36462
  },
36444
- children: resolveDescriptor2(children, "gs-children")
36463
+ children
36445
36464
  }
36446
36465
  )
36447
36466
  ]
@@ -45115,6 +45134,7 @@ var init_WizardContainer = __esm({
45115
45134
  init_Stack();
45116
45135
  init_Icon();
45117
45136
  init_cn();
45137
+ init_useEventBus();
45118
45138
  WizardContainer = ({
45119
45139
  steps,
45120
45140
  currentStep: controlledStep,
@@ -45123,9 +45143,13 @@ var init_WizardContainer = __esm({
45123
45143
  showProgress = true,
45124
45144
  allowBack = true,
45125
45145
  compact = false,
45126
- className
45146
+ className,
45147
+ nextEvent,
45148
+ backEvent,
45149
+ completeEvent
45127
45150
  }) => {
45128
45151
  const { t } = useTranslate();
45152
+ const eventBus = useEventBus();
45129
45153
  const [internalStep, setInternalStep] = useState(0);
45130
45154
  const normalizedControlledStep = (() => {
45131
45155
  if (controlledStep === void 0 || controlledStep === null)
@@ -45155,13 +45179,16 @@ var init_WizardContainer = __esm({
45155
45179
  return;
45156
45180
  }
45157
45181
  if (isLastStep) {
45182
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, { step: currentStep });
45158
45183
  onComplete?.();
45159
45184
  } else {
45185
+ if (nextEvent) eventBus.emit(`UI:${nextEvent}`, { step: currentStep + 1 });
45160
45186
  goToStep(currentStep + 1);
45161
45187
  }
45162
45188
  };
45163
45189
  const handleBack = () => {
45164
45190
  if (!isFirstStep && allowBack) {
45191
+ if (backEvent) eventBus.emit(`UI:${backEvent}`, { step: currentStep - 1 });
45165
45192
  goToStep(currentStep - 1);
45166
45193
  }
45167
45194
  };
@@ -47846,14 +47873,18 @@ var init_DrawerSlot = __esm({
47846
47873
  title: overrideTitle,
47847
47874
  position = "right",
47848
47875
  size = "md",
47849
- className
47876
+ className,
47877
+ sourceTrait
47850
47878
  }) => {
47851
47879
  const eventBus = useEventBus();
47880
+ const schemaCtx = useEntitySchemaOptional();
47852
47881
  const isOpen = Boolean(children);
47853
47882
  const title = overrideTitle || extractTitle(children);
47854
47883
  const handleClose = () => {
47855
- eventBus.emit("UI:CLOSE");
47856
- eventBus.emit("UI:CANCEL");
47884
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
47885
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
47886
+ eventBus.emit(`${prefix}CLOSE`);
47887
+ eventBus.emit(`${prefix}CANCEL`);
47857
47888
  };
47858
47889
  if (!isOpen) return null;
47859
47890
  return /* @__PURE__ */ jsx(
@@ -49824,14 +49855,18 @@ var init_ModalSlot = __esm({
49824
49855
  children,
49825
49856
  title: overrideTitle,
49826
49857
  size = "md",
49827
- className
49858
+ className,
49859
+ sourceTrait
49828
49860
  }) => {
49829
49861
  const eventBus = useEventBus();
49862
+ const schemaCtx = useEntitySchemaOptional();
49830
49863
  const isOpen = Boolean(children);
49831
49864
  const title = overrideTitle || extractTitle2(children);
49832
49865
  const handleClose = () => {
49833
- eventBus.emit("UI:CLOSE");
49834
- eventBus.emit("UI:CANCEL");
49866
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
49867
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
49868
+ eventBus.emit(`${prefix}CLOSE`);
49869
+ eventBus.emit(`${prefix}CANCEL`);
49835
49870
  };
49836
49871
  if (!isOpen) return null;
49837
49872
  return /* @__PURE__ */ jsx(
@@ -53396,17 +53431,21 @@ var init_ToastSlot = __esm({
53396
53431
  variant: overrideVariant,
53397
53432
  title: overrideTitle,
53398
53433
  duration = 5e3,
53399
- className
53434
+ className,
53435
+ sourceTrait
53400
53436
  }) => {
53401
53437
  const eventBus = useEventBus();
53438
+ const schemaCtx = useEntitySchemaOptional();
53402
53439
  const isVisible = Boolean(children);
53403
53440
  const extracted = extractToastProps(children);
53404
53441
  const variant = overrideVariant || extracted.variant || "info";
53405
53442
  const title = overrideTitle || extracted.title;
53406
53443
  const message = extracted.message || (typeof children === "string" ? children : "");
53407
53444
  const handleDismiss = () => {
53408
- eventBus.emit("UI:DISMISS");
53409
- eventBus.emit("UI:CLOSE");
53445
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
53446
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
53447
+ eventBus.emit(`${prefix}DISMISS`);
53448
+ eventBus.emit(`${prefix}CLOSE`);
53410
53449
  };
53411
53450
  if (!isVisible) return null;
53412
53451
  const isCustomContent = React79__default.isValidElement(children) && !message;
@@ -54133,8 +54172,8 @@ function getSlotFallback(slot, config) {
54133
54172
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
54134
54173
  return /* @__PURE__ */ jsx(Skeleton, { variant });
54135
54174
  }
54136
- function getComponentForPattern3(patternType) {
54137
- const mapping = getComponentForPattern(patternType);
54175
+ function getComponentForPattern(patternType) {
54176
+ const mapping = getComponentForPattern$1(patternType);
54138
54177
  if (!mapping) {
54139
54178
  return null;
54140
54179
  }
@@ -54342,6 +54381,7 @@ function UISlotComponent({
54342
54381
  const { t } = useTranslate();
54343
54382
  const suspenseConfig = useContext(SuspenseConfigContext);
54344
54383
  const contained = useContext(SlotContainedContext);
54384
+ const schemaCtx = useEntitySchemaOptional();
54345
54385
  const content = slots[slot];
54346
54386
  if (children !== void 0) {
54347
54387
  if (pattern === "clear") {
@@ -54387,8 +54427,11 @@ function UISlotComponent({
54387
54427
  }
54388
54428
  const handleDismiss = () => {
54389
54429
  if (slot === "modal" || slot === "drawer") {
54390
- eventBus.emit("UI:CLOSE");
54391
- eventBus.emit("UI:CANCEL");
54430
+ const trait = content?.sourceTrait;
54431
+ const orbital = trait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(trait) : void 0;
54432
+ const prefix = orbital !== void 0 && trait !== void 0 ? `UI:${orbital}.${trait}.` : "UI:";
54433
+ eventBus.emit(`${prefix}CLOSE`);
54434
+ eventBus.emit(`${prefix}CANCEL`);
54392
54435
  }
54393
54436
  clear(slot);
54394
54437
  };
@@ -54442,6 +54485,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54442
54485
  const slotsBus = useUISlots();
54443
54486
  const eventBus = useEventBus();
54444
54487
  const { t } = useTranslate();
54488
+ const compiledPortalSchemaCtx = useEntitySchemaOptional();
54445
54489
  useEffect(() => {
54446
54490
  setPortalRoot(getOrCreatePortalRoot());
54447
54491
  }, []);
@@ -54450,8 +54494,10 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54450
54494
  });
54451
54495
  const handleDismiss = () => {
54452
54496
  if (slot === "modal" || slot === "drawer") {
54453
- eventBus.emit("UI:CLOSE");
54454
- eventBus.emit("UI:CANCEL");
54497
+ const orbital = sourceTrait !== void 0 && compiledPortalSchemaCtx !== null ? compiledPortalSchemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
54498
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
54499
+ eventBus.emit(`${prefix}CLOSE`);
54500
+ eventBus.emit(`${prefix}CANCEL`);
54455
54501
  }
54456
54502
  slotsBus.clear(slot);
54457
54503
  };
@@ -54654,7 +54700,7 @@ function isPatternConfig(value) {
54654
54700
  if (value instanceof Date) return false;
54655
54701
  if (typeof value === "function") return false;
54656
54702
  const record = value;
54657
- return "type" in record && typeof record.type === "string" && getComponentForPattern(record.type) !== null;
54703
+ return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
54658
54704
  }
54659
54705
  function isPlainConfigObject(value) {
54660
54706
  if (React79__default.isValidElement(value)) return false;
@@ -54763,7 +54809,7 @@ function SlotContentRenderer({
54763
54809
  }
54764
54810
  }
54765
54811
  const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
54766
- const PatternComponent = getComponentForPattern3(content.pattern);
54812
+ const PatternComponent = getComponentForPattern(content.pattern);
54767
54813
  if (PatternComponent) {
54768
54814
  const childrenConfig = content.props.children;
54769
54815
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -55010,6 +55056,7 @@ var init_UISlotRenderer = __esm({
55010
55056
  "custom",
55011
55057
  "dashboard-layout",
55012
55058
  "game-shell",
55059
+ "game-template",
55013
55060
  "scaled-diagram",
55014
55061
  "master-detail",
55015
55062
  "form-field",
@@ -55049,7 +55096,7 @@ function TraitFrame({
55049
55096
  if (!content) {
55050
55097
  return /* @__PURE__ */ jsx(Fragment, { children: fallback });
55051
55098
  }
55052
- const SlotContentRenderer2 = getSlotContentRenderer3();
55099
+ const SlotContentRenderer2 = getSlotContentRenderer();
55053
55100
  const rendered = /* @__PURE__ */ jsx(
55054
55101
  SlotContentRenderer2,
55055
55102
  {
@@ -55063,7 +55110,7 @@ function TraitFrame({
55063
55110
  }
55064
55111
  return /* @__PURE__ */ jsx(TraitScopeProvider, { orbital, trait: traitName, children: rendered });
55065
55112
  }
55066
- function getSlotContentRenderer3() {
55113
+ function getSlotContentRenderer() {
55067
55114
  if (_slotContentRenderer) return _slotContentRenderer;
55068
55115
  const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
55069
55116
  _slotContentRenderer = mod.SlotContentRenderer;