@almadar/ui 5.79.2 → 5.80.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 +1673 -1590
  2. package/dist/avl/index.css +3 -3
  3. package/dist/avl/index.js +464 -381
  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 +270 -155
  66. package/dist/components/index.css +3 -3
  67. package/dist/components/index.js +272 -157
  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 +1536 -1453
  75. package/dist/providers/index.css +3 -3
  76. package/dist/providers/index.js +436 -353
  77. package/dist/runtime/index.cjs +1530 -1447
  78. package/dist/runtime/index.css +3 -3
  79. package/dist/runtime/index.js +440 -357
  80. package/package.json +1 -1
@@ -40,8 +40,8 @@ var core$1 = require('@almadar/core');
40
40
  var core = require('@dnd-kit/core');
41
41
  var sortable = require('@dnd-kit/sortable');
42
42
  var utilities = require('@dnd-kit/utilities');
43
- var patterns = require('@almadar/patterns');
44
43
  var react = require('@xyflow/react');
44
+ var patterns = require('@almadar/patterns');
45
45
  var reactQuery = require('@tanstack/react-query');
46
46
 
47
47
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -7982,8 +7982,10 @@ function ActionButton({
7982
7982
  size = "md",
7983
7983
  variant = "primary",
7984
7984
  onClick,
7985
+ action,
7985
7986
  className
7986
7987
  }) {
7988
+ const eventBus = useEventBus();
7987
7989
  const sizes = sizeMap[size];
7988
7990
  const onCooldown = cooldown > 0;
7989
7991
  const isDisabled = disabled || onCooldown;
@@ -7993,7 +7995,10 @@ function ActionButton({
7993
7995
  {
7994
7996
  type: "button",
7995
7997
  disabled: isDisabled,
7996
- onClick,
7998
+ onClick: (e) => {
7999
+ if (action) eventBus.emit(`UI:${action}`, {});
8000
+ onClick?.();
8001
+ },
7997
8002
  className: cn(
7998
8003
  "relative inline-flex items-center gap-1.5 rounded-interactive border font-medium overflow-hidden transition-colors duration-150",
7999
8004
  sizes.button,
@@ -8050,6 +8055,7 @@ var init_ActionButton = __esm({
8050
8055
  "components/game/2d/atoms/ActionButton.tsx"() {
8051
8056
  init_cn();
8052
8057
  init_Icon();
8058
+ init_useEventBus();
8053
8059
  sizeMap = {
8054
8060
  sm: { button: "h-button-sm px-3 text-xs", hotkey: "text-[9px] px-1", icon: "text-xs" },
8055
8061
  md: { button: "h-button-md px-4 text-sm", hotkey: "text-xs px-1.5", icon: "text-sm" },
@@ -8103,7 +8109,7 @@ function ActionTile({
8103
8109
  draggable: !disabled,
8104
8110
  onDragStart: handleDragStart,
8105
8111
  children: [
8106
- action.iconUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: action.iconUrl, alt: "", className: "w-8 h-8 object-contain" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8112
+ action.iconUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: action.iconUrl.url, alt: "", className: "w-8 h-8 object-contain" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8107
8113
  /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: cn(config.text, "text-foreground font-medium whitespace-nowrap"), children: action.name })
8108
8114
  ]
8109
8115
  }
@@ -8707,9 +8713,26 @@ function MiniMap({
8707
8713
  mapWidth = 100,
8708
8714
  mapHeight = 100,
8709
8715
  viewportRect = DEFAULT_VIEWPORT,
8710
- className
8716
+ className,
8717
+ tileAssets,
8718
+ unitAssets
8711
8719
  }) {
8712
8720
  const canvasRef = React79__namespace.useRef(null);
8721
+ const imgCacheRef = React79__namespace.useRef(/* @__PURE__ */ new Map());
8722
+ function loadImg(url) {
8723
+ const cached = imgCacheRef.current.get(url);
8724
+ if (cached) return cached.complete ? cached : null;
8725
+ const img = new Image();
8726
+ img.src = url;
8727
+ img.onload = () => {
8728
+ const canvas = canvasRef.current;
8729
+ if (!canvas) return;
8730
+ const ctx = canvas.getContext("2d");
8731
+ if (ctx) ctx.clearRect(0, 0, 0, 0);
8732
+ };
8733
+ imgCacheRef.current.set(url, img);
8734
+ return null;
8735
+ }
8713
8736
  React79__namespace.useEffect(() => {
8714
8737
  const canvas = canvasRef.current;
8715
8738
  if (!canvas) return;
@@ -8721,20 +8744,31 @@ function MiniMap({
8721
8744
  ctx.fillStyle = "#111";
8722
8745
  ctx.fillRect(0, 0, width, height);
8723
8746
  for (const tile of tiles) {
8724
- ctx.fillStyle = tile.color;
8725
- ctx.fillRect(
8726
- Math.floor(tile.x * scaleX2),
8727
- Math.floor(tile.y * scaleY2),
8728
- Math.max(1, Math.ceil(scaleX2)),
8729
- Math.max(1, Math.ceil(scaleY2))
8730
- );
8747
+ const tileAsset = tileAssets?.[tile.color] ?? tileAssets?.["default"];
8748
+ const tileImg = tileAsset ? loadImg(tileAsset.url) : null;
8749
+ const tx = Math.floor(tile.x * scaleX2);
8750
+ const ty = Math.floor(tile.y * scaleY2);
8751
+ const tw = Math.max(1, Math.ceil(scaleX2));
8752
+ const th = Math.max(1, Math.ceil(scaleY2));
8753
+ if (tileImg) {
8754
+ ctx.drawImage(tileImg, tx, ty, tw, th);
8755
+ } else {
8756
+ ctx.fillStyle = tile.color;
8757
+ ctx.fillRect(tx, ty, tw, th);
8758
+ }
8731
8759
  }
8732
8760
  for (const unit of units) {
8733
8761
  if (unit.isPlayer) continue;
8734
- ctx.fillStyle = unit.color;
8762
+ const unitAsset = unitAssets?.[unit.color] ?? unitAssets?.["default"];
8763
+ const unitImg = unitAsset ? loadImg(unitAsset.url) : null;
8735
8764
  const ux = Math.floor(unit.x * scaleX2) - 1;
8736
8765
  const uy = Math.floor(unit.y * scaleY2) - 1;
8737
- ctx.fillRect(ux, uy, 3, 3);
8766
+ if (unitImg) {
8767
+ ctx.drawImage(unitImg, ux, uy, 5, 5);
8768
+ } else {
8769
+ ctx.fillStyle = unit.color;
8770
+ ctx.fillRect(ux, uy, 3, 3);
8771
+ }
8738
8772
  }
8739
8773
  if (viewportRect) {
8740
8774
  ctx.strokeStyle = "#ffffff";
@@ -8746,7 +8780,7 @@ function MiniMap({
8746
8780
  Math.floor(viewportRect.h * scaleY2)
8747
8781
  );
8748
8782
  }
8749
- }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect]);
8783
+ }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect, tileAssets, unitAssets]);
8750
8784
  const scaleX = width / mapWidth;
8751
8785
  const scaleY = height / mapHeight;
8752
8786
  const playerUnit = units.find((u) => u.isPlayer);
@@ -8823,7 +8857,9 @@ function HealthBar({
8823
8857
  labelSuffix,
8824
8858
  size = "md",
8825
8859
  className,
8826
- animated = true
8860
+ animated = true,
8861
+ frameAsset,
8862
+ fillAsset
8827
8863
  }) {
8828
8864
  const sizes = sizeMap2[size];
8829
8865
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
@@ -8842,20 +8878,25 @@ function HealthBar({
8842
8878
  "div",
8843
8879
  {
8844
8880
  className: cn(
8845
- "relative overflow-hidden rounded-full bg-muted",
8881
+ "relative overflow-hidden rounded-full",
8882
+ !frameAsset && "bg-muted",
8846
8883
  sizes.bar,
8847
8884
  "w-24",
8848
8885
  className
8849
8886
  ),
8887
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8850
8888
  children: /* @__PURE__ */ jsxRuntime.jsx(
8851
8889
  "div",
8852
8890
  {
8853
8891
  className: cn(
8854
8892
  "absolute inset-y-0 left-0 rounded-full",
8855
- percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error",
8893
+ !fillAsset && (percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error"),
8856
8894
  animated && "transition-all duration-300"
8857
8895
  ),
8858
- style: { width: `${percentage}%` }
8896
+ style: {
8897
+ width: `${percentage}%`,
8898
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8899
+ }
8859
8900
  }
8860
8901
  )
8861
8902
  }
@@ -8882,18 +8923,23 @@ function HealthBar({
8882
8923
  "div",
8883
8924
  {
8884
8925
  className: cn(
8885
- "relative w-full overflow-hidden rounded-full bg-muted border border-muted",
8926
+ "relative w-full overflow-hidden rounded-full",
8927
+ !frameAsset && "bg-muted border border-muted",
8886
8928
  sizes.bar
8887
8929
  ),
8930
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8888
8931
  children: /* @__PURE__ */ jsxRuntime.jsx(
8889
8932
  "div",
8890
8933
  {
8891
8934
  className: cn(
8892
8935
  "absolute inset-y-0 left-0 rounded-full",
8893
- "bg-gradient-to-r from-accent to-info",
8936
+ !fillAsset && "bg-gradient-to-r from-accent to-info",
8894
8937
  animated && "transition-all duration-500 ease-out"
8895
8938
  ),
8896
- style: { width: `${percentage}%` }
8939
+ style: {
8940
+ width: `${percentage}%`,
8941
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8942
+ }
8897
8943
  }
8898
8944
  )
8899
8945
  }
@@ -12675,9 +12721,9 @@ var init_BiologyCanvas = __esm({
12675
12721
  }
12676
12722
  });
12677
12723
 
12678
- // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
12724
+ // node_modules/katex/dist/katex.min.css
12679
12725
  var init_katex_min = __esm({
12680
- "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
12726
+ "node_modules/katex/dist/katex.min.css"() {
12681
12727
  }
12682
12728
  });
12683
12729
  exports.Tabs = void 0;
@@ -21484,14 +21530,19 @@ function ChoiceButton({
21484
21530
  disabled = false,
21485
21531
  selected = false,
21486
21532
  onClick,
21533
+ action,
21487
21534
  className
21488
21535
  }) {
21536
+ const eventBus = useEventBus();
21489
21537
  return /* @__PURE__ */ jsxRuntime.jsxs(
21490
21538
  "button",
21491
21539
  {
21492
21540
  type: "button",
21493
21541
  disabled,
21494
- onClick,
21542
+ onClick: (e) => {
21543
+ if (action) eventBus.emit(`UI:${action}`, {});
21544
+ onClick?.();
21545
+ },
21495
21546
  className: cn(
21496
21547
  "w-full text-left px-4 py-2.5 rounded-interactive border transition-all duration-150",
21497
21548
  "flex items-center gap-2",
@@ -21539,6 +21590,7 @@ var init_ChoiceButton = __esm({
21539
21590
  "components/game/2d/atoms/ChoiceButton.tsx"() {
21540
21591
  init_cn();
21541
21592
  init_Icon();
21593
+ init_useEventBus();
21542
21594
  ChoiceButton.displayName = "ChoiceButton";
21543
21595
  }
21544
21596
  });
@@ -22584,6 +22636,7 @@ function ControlGrid({
22584
22636
  actionEvent,
22585
22637
  onDirection,
22586
22638
  directionEvent,
22639
+ directionAssets,
22587
22640
  size = "md",
22588
22641
  disabled,
22589
22642
  className
@@ -22623,7 +22676,8 @@ function ControlGrid({
22623
22676
  const dir = (d) => /* @__PURE__ */ jsxRuntime.jsx(
22624
22677
  ControlButton,
22625
22678
  {
22626
- icon: arrowIcons[d],
22679
+ icon: directionAssets?.[d] ? void 0 : arrowIcons[d],
22680
+ assetUrl: directionAssets?.[d],
22627
22681
  size: sizeKey[size],
22628
22682
  variant: "secondary",
22629
22683
  pressed: active.has(d),
@@ -22764,6 +22818,8 @@ function CounterMinimal({
22764
22818
  size = "md",
22765
22819
  onDecrement,
22766
22820
  onIncrement,
22821
+ decrementEvent,
22822
+ incrementEvent,
22767
22823
  className
22768
22824
  }) {
22769
22825
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22774,6 +22830,7 @@ function CounterMinimal({
22774
22830
  {
22775
22831
  variant: "secondary",
22776
22832
  size: sizeStyles8[size].button,
22833
+ action: decrementEvent,
22777
22834
  onClick: onDecrement,
22778
22835
  disabled: resolved.decrementDisabled,
22779
22836
  icon: "minus",
@@ -22796,6 +22853,7 @@ function CounterMinimal({
22796
22853
  {
22797
22854
  variant: "secondary",
22798
22855
  size: sizeStyles8[size].button,
22856
+ action: incrementEvent,
22799
22857
  onClick: onIncrement,
22800
22858
  disabled: resolved.incrementDisabled,
22801
22859
  icon: "plus",
@@ -22812,6 +22870,9 @@ function CounterStandard({
22812
22870
  onDecrement,
22813
22871
  onIncrement,
22814
22872
  onReset,
22873
+ decrementEvent,
22874
+ incrementEvent,
22875
+ resetEvent,
22815
22876
  className
22816
22877
  }) {
22817
22878
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22842,6 +22903,7 @@ function CounterStandard({
22842
22903
  {
22843
22904
  variant: "secondary",
22844
22905
  size: sizeStyles8[size].button,
22906
+ action: decrementEvent,
22845
22907
  onClick: onDecrement,
22846
22908
  disabled: resolved.decrementDisabled,
22847
22909
  icon: "minus"
@@ -22852,6 +22914,7 @@ function CounterStandard({
22852
22914
  {
22853
22915
  variant: "primary",
22854
22916
  size: sizeStyles8[size].button,
22917
+ action: incrementEvent,
22855
22918
  onClick: onIncrement,
22856
22919
  disabled: resolved.incrementDisabled,
22857
22920
  icon: "plus"
@@ -22863,6 +22926,7 @@ function CounterStandard({
22863
22926
  {
22864
22927
  variant: "ghost",
22865
22928
  size: "sm",
22929
+ action: resetEvent,
22866
22930
  onClick: onReset,
22867
22931
  icon: "rotate-ccw",
22868
22932
  children: "Reset"
@@ -22878,6 +22942,9 @@ function CounterFull({
22878
22942
  onDecrement,
22879
22943
  onIncrement,
22880
22944
  onReset,
22945
+ decrementEvent,
22946
+ incrementEvent,
22947
+ resetEvent,
22881
22948
  className
22882
22949
  }) {
22883
22950
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22911,6 +22978,7 @@ function CounterFull({
22911
22978
  {
22912
22979
  variant: "secondary",
22913
22980
  size: sizeStyles8[size].button,
22981
+ action: decrementEvent,
22914
22982
  onClick: onDecrement,
22915
22983
  disabled: resolved.decrementDisabled,
22916
22984
  icon: "minus",
@@ -22922,6 +22990,7 @@ function CounterFull({
22922
22990
  {
22923
22991
  variant: "primary",
22924
22992
  size: sizeStyles8[size].button,
22993
+ action: incrementEvent,
22925
22994
  onClick: onIncrement,
22926
22995
  disabled: resolved.incrementDisabled,
22927
22996
  icon: "plus",
@@ -22934,6 +23003,7 @@ function CounterFull({
22934
23003
  {
22935
23004
  variant: "ghost",
22936
23005
  size: "sm",
23006
+ action: resetEvent,
22937
23007
  onClick: onReset,
22938
23008
  icon: "rotate-ccw",
22939
23009
  children: "Reset to 0"
@@ -29630,14 +29700,15 @@ function TimerDisplay({
29630
29700
  format = "mm:ss",
29631
29701
  size = "md",
29632
29702
  className,
29633
- lowThreshold
29703
+ lowThreshold,
29704
+ iconAsset
29634
29705
  }) {
29635
29706
  const isLow = lowThreshold != null && seconds <= lowThreshold && seconds > 0;
29636
- return /* @__PURE__ */ jsxRuntime.jsx(
29707
+ return /* @__PURE__ */ jsxRuntime.jsxs(
29637
29708
  "div",
29638
29709
  {
29639
29710
  className: cn(
29640
- "inline-flex items-center justify-center rounded-container",
29711
+ "inline-flex items-center gap-1 justify-center rounded-container",
29641
29712
  "bg-card/80 border border-muted font-mono font-bold tabular-nums",
29642
29713
  sizeMap9[size],
29643
29714
  running && "border-success/50",
@@ -29645,7 +29716,10 @@ function TimerDisplay({
29645
29716
  !isLow && "text-foreground",
29646
29717
  className
29647
29718
  ),
29648
- children: formatTime(seconds, format)
29719
+ children: [
29720
+ iconAsset && /* @__PURE__ */ jsxRuntime.jsx("img", { src: iconAsset.url, alt: "", className: "w-4 h-4 object-contain flex-shrink-0" }),
29721
+ formatTime(seconds, format)
29722
+ ]
29649
29723
  }
29650
29724
  );
29651
29725
  }
@@ -29741,15 +29815,20 @@ function ItemSlot({
29741
29815
  size = "md",
29742
29816
  selected,
29743
29817
  onClick,
29818
+ action,
29744
29819
  className
29745
29820
  }) {
29746
- const isClickable = onClick != null;
29821
+ const eventBus = useEventBus();
29822
+ const isClickable = onClick != null || action != null;
29747
29823
  const px = assetSizeMap[size];
29748
29824
  return /* @__PURE__ */ jsxRuntime.jsx(
29749
29825
  "button",
29750
29826
  {
29751
29827
  type: "button",
29752
- onClick,
29828
+ onClick: () => {
29829
+ if (action) eventBus.emit(`UI:${action}`, {});
29830
+ onClick?.();
29831
+ },
29753
29832
  disabled: !isClickable,
29754
29833
  title: label,
29755
29834
  className: cn(
@@ -29797,6 +29876,7 @@ var init_ItemSlot = __esm({
29797
29876
  "use client";
29798
29877
  init_cn();
29799
29878
  init_Icon();
29879
+ init_useEventBus();
29800
29880
  sizeMap11 = {
29801
29881
  sm: "w-10 h-10 text-lg",
29802
29882
  md: "w-14 h-14 text-2xl",
@@ -30223,7 +30303,7 @@ function InventoryGrid({
30223
30303
  (id) => {
30224
30304
  onSelect?.(id);
30225
30305
  if (selectEvent) {
30226
- eventBus.emit(selectEvent, { id });
30306
+ eventBus.emit(`UI:${selectEvent}`, { id });
30227
30307
  }
30228
30308
  },
30229
30309
  [onSelect, selectEvent, eventBus]
@@ -30428,27 +30508,21 @@ function GameMenu({
30428
30508
  options,
30429
30509
  menuItems,
30430
30510
  onSelect,
30431
- eventBus: eventBusProp,
30432
30511
  background,
30433
- logo = "",
30512
+ logo,
30434
30513
  className
30435
30514
  }) {
30436
30515
  const resolvedOptions = options ?? menuItems ?? DEFAULT_MENU_OPTIONS;
30437
- let eventBusFromHook = null;
30438
- try {
30439
- eventBusFromHook = useEventBus();
30440
- } catch {
30441
- }
30442
- const eventBus = eventBusProp || eventBusFromHook;
30516
+ const eventBus = useEventBus();
30443
30517
  const handleOptionClick = React79__namespace.useCallback(
30444
30518
  (option) => {
30445
- if (option.event && eventBus) {
30519
+ if (option.event) {
30446
30520
  eventBus.emit(`UI:${option.event}`, { option });
30447
30521
  }
30448
30522
  if (onSelect) {
30449
30523
  onSelect(option);
30450
30524
  }
30451
- if (option.navigatesTo && eventBus) {
30525
+ if (option.navigatesTo) {
30452
30526
  eventBus.emit("UI:NAVIGATE", { url: option.navigatesTo, option });
30453
30527
  }
30454
30528
  },
@@ -30469,7 +30543,7 @@ function GameMenu({
30469
30543
  logo && /* @__PURE__ */ jsxRuntime.jsx(
30470
30544
  "img",
30471
30545
  {
30472
- src: logo,
30546
+ src: logo.url,
30473
30547
  alt: title,
30474
30548
  className: "h-24 w-auto mx-auto mb-6 drop-shadow-2xl"
30475
30549
  }
@@ -30929,7 +31003,9 @@ var init_GameAudioProvider = __esm({
30929
31003
  });
30930
31004
  function GameAudioToggle({
30931
31005
  size = "sm",
30932
- className
31006
+ className,
31007
+ onAsset,
31008
+ offAsset
30933
31009
  }) {
30934
31010
  const ctx = useGameAudioContextOptional();
30935
31011
  const [localMuted, setLocalMuted] = React79.useState(false);
@@ -30938,6 +31014,7 @@ function GameAudioToggle({
30938
31014
  const handleToggle = React79.useCallback(() => {
30939
31015
  setMuted(!muted);
30940
31016
  }, [muted, setMuted]);
31017
+ const activeAsset = muted ? offAsset : onAsset;
30941
31018
  return /* @__PURE__ */ jsxRuntime.jsx(
30942
31019
  exports.Button,
30943
31020
  {
@@ -30946,7 +31023,7 @@ function GameAudioToggle({
30946
31023
  onClick: handleToggle,
30947
31024
  className: cn("text-lg leading-none px-2", className),
30948
31025
  "aria-pressed": muted,
30949
- children: muted ? "\u{1F507}" : "\u{1F50A}"
31026
+ children: activeAsset ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: activeAsset.url, alt: muted ? "Muted" : "Sound on", className: "w-5 h-5 object-contain" }) : muted ? "\u{1F507}" : "\u{1F50A}"
30950
31027
  }
30951
31028
  );
30952
31029
  }
@@ -31535,6 +31612,7 @@ function PlatformerBoard({
31535
31612
  canvasHeight: _canvasHeight = 400,
31536
31613
  playerSprite,
31537
31614
  tileSprites,
31615
+ ui: _ui,
31538
31616
  bgColor: _bgColor,
31539
31617
  keyEvent = "KEY",
31540
31618
  playAgainEvent = "PLAY_AGAIN",
@@ -32959,6 +33037,7 @@ function TanksBoard({
32959
33037
  features,
32960
33038
  assetManifest,
32961
33039
  assetBaseUrl,
33040
+ ui: _ui,
32962
33041
  scale = 0.45,
32963
33042
  showMinimap = true,
32964
33043
  enableCamera = true,
@@ -33666,7 +33745,7 @@ function TraitSlot({
33666
33745
  size = "md",
33667
33746
  showTooltip = true,
33668
33747
  categoryColors,
33669
- tooltipFrameUrl = "",
33748
+ tooltipFrameUrl,
33670
33749
  className,
33671
33750
  feedback,
33672
33751
  onItemDrop,
@@ -33796,7 +33875,7 @@ function TraitSlot({
33796
33875
  as: "img",
33797
33876
  className: "object-contain",
33798
33877
  style: { width: config.icon, height: config.icon },
33799
- ...{ src: equippedItem.iconUrl, alt: equippedItem.name }
33878
+ ...{ src: equippedItem.iconUrl.url, alt: equippedItem.name }
33800
33879
  }
33801
33880
  ) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "text-center leading-none", style: { fontSize: config.icon }, children: equippedItem.iconEmoji || "\u2726" }),
33802
33881
  (onRemove || removeEvent) && /* @__PURE__ */ jsxRuntime.jsx(
@@ -33825,7 +33904,7 @@ function TraitSlot({
33825
33904
  ...getTooltipStyle(),
33826
33905
  minWidth: 200,
33827
33906
  ...tooltipFrameUrl ? {
33828
- borderImage: `url(${tooltipFrameUrl}) 60 fill / 15px / 0 stretch`,
33907
+ borderImage: `url(${tooltipFrameUrl.url}) 60 fill / 15px / 0 stretch`,
33829
33908
  border: "none"
33830
33909
  } : {}
33831
33910
  },
@@ -34122,6 +34201,42 @@ function computeSlotFeedback(playerSeq, solutions) {
34122
34201
  (id, i) => id !== void 0 && id === bestSolution[i] ? "correct" : "wrong"
34123
34202
  );
34124
34203
  }
34204
+ function isFieldRecord(v) {
34205
+ return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Date);
34206
+ }
34207
+ function assetFromField(v) {
34208
+ if (!isFieldRecord(v)) return void 0;
34209
+ const url = typeof v.url === "string" ? v.url : void 0;
34210
+ const role = typeof v.role === "string" ? v.role : void 0;
34211
+ const category = typeof v.category === "string" ? v.category : "";
34212
+ if (!url || !role) return void 0;
34213
+ return {
34214
+ url,
34215
+ role,
34216
+ category,
34217
+ name: typeof v.name === "string" ? v.name : void 0,
34218
+ thumbnailUrl: typeof v.thumbnailUrl === "string" ? v.thumbnailUrl : void 0,
34219
+ style: typeof v.style === "string" ? v.style : void 0,
34220
+ variant: typeof v.variant === "string" ? v.variant : void 0,
34221
+ dimension: typeof v.dimension === "string" ? v.dimension : void 0,
34222
+ aspect: typeof v.aspect === "string" ? v.aspect : void 0
34223
+ };
34224
+ }
34225
+ function slotItemFromField(fv) {
34226
+ if (!isFieldRecord(fv)) return void 0;
34227
+ const id = typeof fv.id === "string" ? fv.id : void 0;
34228
+ const name = typeof fv.name === "string" ? fv.name : void 0;
34229
+ const category = typeof fv.category === "string" ? fv.category : void 0;
34230
+ if (!id || !name || !category) return void 0;
34231
+ return {
34232
+ id,
34233
+ name,
34234
+ category,
34235
+ description: typeof fv.description === "string" ? fv.description : void 0,
34236
+ iconEmoji: typeof fv.iconEmoji === "string" ? fv.iconEmoji : void 0,
34237
+ iconUrl: assetFromField(fv.iconUrl)
34238
+ };
34239
+ }
34125
34240
  function SequencerBoard({
34126
34241
  entity,
34127
34242
  categoryColors,
@@ -34132,6 +34247,7 @@ function SequencerBoard({
34132
34247
  removeEvent,
34133
34248
  checkEvent,
34134
34249
  playAgainEvent,
34250
+ stepEvent,
34135
34251
  className
34136
34252
  }) {
34137
34253
  const { emit } = useEventBus();
@@ -34139,7 +34255,11 @@ function SequencerBoard({
34139
34255
  const resolved = boardEntity(entity);
34140
34256
  const maxSlots = num(resolved?.maxSlots) || 3;
34141
34257
  const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
34142
- const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
34258
+ const availableActions = (Array.isArray(resolved?.availableActions) ? resolved.availableActions : []).reduce((acc, fv) => {
34259
+ const item = slotItemFromField(fv);
34260
+ if (item) acc.push(item);
34261
+ return acc;
34262
+ }, []);
34143
34263
  const allowDuplicates = resolved?.allowDuplicates !== false;
34144
34264
  const entitySlots = Array.isArray(resolved?.slots) ? resolved.slots : [];
34145
34265
  const entityResult = str(resolved?.result);
@@ -34197,7 +34317,7 @@ function SequencerBoard({
34197
34317
  let step = 0;
34198
34318
  const advance = () => {
34199
34319
  step++;
34200
- emit("UI:STEP", { step });
34320
+ if (stepEvent) emit(`UI:${stepEvent}`, { step });
34201
34321
  if (step >= maxSlots) {
34202
34322
  if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
34203
34323
  const playerSeq = slots.map((s) => s?.id);
@@ -36096,24 +36216,55 @@ function SimulationControls({
36096
36216
  onReset,
36097
36217
  onSpeedChange,
36098
36218
  onParameterChange,
36219
+ playEvent,
36220
+ pauseEvent,
36221
+ stepEvent,
36222
+ resetEvent,
36223
+ speedChangeEvent,
36224
+ parameterChangeEvent,
36099
36225
  assetManifest,
36100
36226
  className
36101
36227
  }) {
36228
+ const eventBus = useEventBus();
36102
36229
  const ui = assetManifest?.ui;
36230
+ const handlePlay = () => {
36231
+ if (playEvent) eventBus.emit(`UI:${playEvent}`, {});
36232
+ onPlay?.();
36233
+ };
36234
+ const handlePause = () => {
36235
+ if (pauseEvent) eventBus.emit(`UI:${pauseEvent}`, {});
36236
+ onPause?.();
36237
+ };
36238
+ const handleStep = () => {
36239
+ if (stepEvent) eventBus.emit(`UI:${stepEvent}`, {});
36240
+ onStep?.();
36241
+ };
36242
+ const handleReset = () => {
36243
+ if (resetEvent) eventBus.emit(`UI:${resetEvent}`, {});
36244
+ onReset?.();
36245
+ };
36246
+ const handleSpeedChange = (s) => {
36247
+ if (speedChangeEvent) eventBus.emit(`UI:${speedChangeEvent}`, { speed: s });
36248
+ onSpeedChange?.(s);
36249
+ };
36250
+ const handleParameterChange = (name, value) => {
36251
+ if (parameterChangeEvent) eventBus.emit(`UI:${parameterChangeEvent}`, { name, value });
36252
+ onParameterChange?.(name, value);
36253
+ };
36103
36254
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "md", className, children: [
36104
36255
  /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", align: "center", children: [
36105
- running ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "secondary", onClick: onPause, children: [
36256
+ running ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "secondary", onClick: handlePause, children: [
36106
36257
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.Pause, assetUrl: ui?.["pause"], size: "sm" }),
36107
36258
  "Pause"
36108
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "primary", onClick: onPlay, children: [
36259
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "primary", onClick: handlePlay, children: [
36109
36260
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.Play, assetUrl: ui?.["play"], size: "sm" }),
36110
36261
  "Play"
36111
36262
  ] }),
36112
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: onStep, disabled: running, children: [
36263
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: handleStep, disabled: running, children: [
36113
36264
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.SkipForward, assetUrl: ui?.["step"], size: "sm" }),
36114
36265
  "Step"
36115
36266
  ] }),
36116
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: onReset, children: [
36267
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: handleReset, children: [
36117
36268
  /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.RotateCcw, assetUrl: ui?.["reset"], size: "sm" }),
36118
36269
  "Reset"
36119
36270
  ] })
@@ -36132,7 +36283,7 @@ function SimulationControls({
36132
36283
  max: 5,
36133
36284
  step: 0.1,
36134
36285
  value: speed,
36135
- onChange: (e) => onSpeedChange(parseFloat(e.target.value)),
36286
+ onChange: (e) => handleSpeedChange(parseFloat(e.target.value)),
36136
36287
  className: "w-full"
36137
36288
  }
36138
36289
  )
@@ -36151,7 +36302,7 @@ function SimulationControls({
36151
36302
  max: param.max,
36152
36303
  step: param.step,
36153
36304
  value: param.value,
36154
- onChange: (e) => onParameterChange(name, parseFloat(e.target.value)),
36305
+ onChange: (e) => handleParameterChange(name, parseFloat(e.target.value)),
36155
36306
  className: "w-full"
36156
36307
  }
36157
36308
  )
@@ -36160,6 +36311,7 @@ function SimulationControls({
36160
36311
  }
36161
36312
  var init_SimulationControls = __esm({
36162
36313
  "components/game/2d/organisms/SimulationControls.tsx"() {
36314
+ init_useEventBus();
36163
36315
  init_atoms();
36164
36316
  init_GameIcon();
36165
36317
  SimulationControls.displayName = "SimulationControls";
@@ -36228,35 +36380,7 @@ var init_SimulationGraph = __esm({
36228
36380
  SimulationGraph.displayName = "SimulationGraph";
36229
36381
  }
36230
36382
  });
36231
- function getSlotContentRenderer() {
36232
- if (_scr) return _scr;
36233
- const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
36234
- _scr = mod.SlotContentRenderer;
36235
- return _scr;
36236
- }
36237
- function resolveDescriptor(value, idPrefix) {
36238
- if (value === null || value === void 0) return value;
36239
- if (React79__namespace.default.isValidElement(value)) return value;
36240
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
36241
- if (Array.isArray(value)) {
36242
- return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React79__namespace.default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
36243
- }
36244
- if (typeof value === "object") {
36245
- const rec = value;
36246
- if (typeof rec.type === "string" && patterns.getComponentForPattern(rec.type) !== null) {
36247
- const type = rec.type;
36248
- const _id = typeof rec._id === "string" ? rec._id : void 0;
36249
- const nestedProps = rec.props !== void 0 && typeof rec.props === "object" && !Array.isArray(rec.props) && rec.props !== null ? rec.props : void 0;
36250
- const { type: _t, props: _p, _id: _d, ...flatRest } = rec;
36251
- const resolvedProps = nestedProps !== void 0 ? nestedProps : flatRest;
36252
- const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
36253
- const SCR = getSlotContentRenderer();
36254
- return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
36255
- }
36256
- }
36257
- return null;
36258
- }
36259
- var _scr; exports.GameTemplate = void 0;
36383
+ exports.GameTemplate = void 0;
36260
36384
  var init_GameTemplate = __esm({
36261
36385
  "components/game/2d/templates/GameTemplate.tsx"() {
36262
36386
  init_cn();
@@ -36264,7 +36388,6 @@ var init_GameTemplate = __esm({
36264
36388
  init_Stack();
36265
36389
  init_Typography();
36266
36390
  init_Button();
36267
- _scr = null;
36268
36391
  exports.GameTemplate = ({
36269
36392
  entity,
36270
36393
  title = "Game",
@@ -36273,7 +36396,8 @@ var init_GameTemplate = __esm({
36273
36396
  debugPanel,
36274
36397
  showDebugPanel = false,
36275
36398
  controls,
36276
- className
36399
+ className,
36400
+ backgroundAsset
36277
36401
  }) => {
36278
36402
  return /* @__PURE__ */ jsxRuntime.jsxs(
36279
36403
  exports.Box,
@@ -36330,15 +36454,16 @@ var init_GameTemplate = __esm({
36330
36454
  {
36331
36455
  position: "relative",
36332
36456
  fullWidth: true,
36333
- className: "flex-1 bg-muted",
36457
+ className: backgroundAsset ? "flex-1" : "flex-1 bg-muted",
36458
+ style: backgroundAsset ? { backgroundImage: `url(${backgroundAsset.url})`, backgroundSize: "cover", backgroundPosition: "center" } : void 0,
36334
36459
  children: [
36335
- resolveDescriptor(children, "gt-children"),
36460
+ children,
36336
36461
  hud && /* @__PURE__ */ jsxRuntime.jsx(
36337
36462
  exports.Box,
36338
36463
  {
36339
36464
  position: "absolute",
36340
36465
  className: "top-0 left-0 right-0 pointer-events-none",
36341
- children: /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", className: "pointer-events-auto w-fit", children: resolveDescriptor(hud, "gt-hud") })
36466
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
36342
36467
  }
36343
36468
  )
36344
36469
  ]
@@ -36363,7 +36488,7 @@ var init_GameTemplate = __esm({
36363
36488
  children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h6", children: "Debug Panel" })
36364
36489
  }
36365
36490
  ),
36366
- /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", children: resolveDescriptor(debugPanel, "gt-debug") })
36491
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { padding: "md", children: debugPanel })
36367
36492
  ]
36368
36493
  }
36369
36494
  )
@@ -36374,59 +36499,21 @@ var init_GameTemplate = __esm({
36374
36499
  exports.GameTemplate.displayName = "GameTemplate";
36375
36500
  }
36376
36501
  });
36377
- function asDescriptor(v) {
36378
- if (Array.isArray(v) || React79__namespace.default.isValidElement(v)) return null;
36379
- const o = v;
36380
- if (typeof o.type !== "string") return null;
36381
- const props = o.props !== void 0 && typeof o.props === "object" && !Array.isArray(o.props) && o.props !== null ? o.props : void 0;
36382
- const _id = typeof o._id === "string" ? o._id : void 0;
36383
- const sourceTrait = typeof o.sourceTrait === "string" ? o.sourceTrait : void 0;
36384
- return { type: o.type, props, _id, sourceTrait };
36385
- }
36386
- function getSlotContentRenderer2() {
36387
- if (_scr2) return _scr2;
36388
- const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
36389
- _scr2 = mod.SlotContentRenderer;
36390
- return _scr2;
36391
- }
36392
- function resolveDescriptor2(value, idPrefix) {
36393
- if (value === null || value === void 0) return value;
36394
- if (React79__namespace.default.isValidElement(value)) return value;
36395
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
36396
- if (Array.isArray(value)) {
36397
- return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React79__namespace.default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
36398
- }
36399
- if (typeof value === "object" && value !== null) {
36400
- const desc = asDescriptor(value);
36401
- if (desc !== null && patterns.getComponentForPattern(desc.type) !== null) {
36402
- const resolvedProps = desc.props ?? {};
36403
- const content = {
36404
- id: desc._id ?? idPrefix,
36405
- pattern: desc.type,
36406
- props: resolvedProps,
36407
- priority: 0,
36408
- ...desc.sourceTrait !== void 0 && { sourceTrait: desc.sourceTrait }
36409
- };
36410
- const SCR = getSlotContentRenderer2();
36411
- return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
36412
- }
36413
- }
36414
- return null;
36415
- }
36416
- var _scr2; exports.GameShell = void 0;
36502
+ exports.GameShell = void 0;
36417
36503
  var init_GameShell = __esm({
36418
36504
  "components/game/2d/templates/GameShell.tsx"() {
36419
36505
  init_cn();
36420
36506
  init_Box();
36421
36507
  init_Stack();
36422
36508
  init_Typography();
36423
- _scr2 = null;
36424
36509
  exports.GameShell = ({
36425
36510
  appName = "Game",
36426
36511
  hud,
36427
36512
  className,
36428
36513
  showTopBar = true,
36429
- children
36514
+ children,
36515
+ backgroundAsset,
36516
+ hudBackgroundAsset
36430
36517
  }) => {
36431
36518
  return /* @__PURE__ */ jsxRuntime.jsxs(
36432
36519
  exports.Box,
@@ -36441,7 +36528,7 @@ var init_GameShell = __esm({
36441
36528
  width: "100vw",
36442
36529
  height: "100vh",
36443
36530
  overflow: "hidden",
36444
- background: "var(--color-background, #0a0a0f)",
36531
+ background: backgroundAsset ? `url(${backgroundAsset.url}) center/cover no-repeat` : "var(--color-background, #0a0a0f)",
36445
36532
  color: "var(--color-text, #e0e0e0)"
36446
36533
  },
36447
36534
  children: [
@@ -36451,7 +36538,7 @@ var init_GameShell = __esm({
36451
36538
  className: "game-shell__header",
36452
36539
  style: {
36453
36540
  flexShrink: 0,
36454
- background: "var(--color-surface, #12121f)",
36541
+ background: hudBackgroundAsset ? `url(${hudBackgroundAsset.url}) center/cover no-repeat` : "var(--color-surface, #12121f)",
36455
36542
  borderBottom: "1px solid var(--color-border, #2a2a3a)"
36456
36543
  },
36457
36544
  children: [
@@ -36474,7 +36561,7 @@ var init_GameShell = __esm({
36474
36561
  )
36475
36562
  }
36476
36563
  ),
36477
- hud && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "game-shell__hud", style: { width: "100%" }, children: resolveDescriptor2(hud, "gs-hud") })
36564
+ hud && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "game-shell__hud", style: { width: "100%" }, children: hud })
36478
36565
  ]
36479
36566
  }
36480
36567
  ),
@@ -36487,7 +36574,7 @@ var init_GameShell = __esm({
36487
36574
  overflow: "hidden",
36488
36575
  position: "relative"
36489
36576
  },
36490
- children: resolveDescriptor2(children, "gs-children")
36577
+ children
36491
36578
  }
36492
36579
  )
36493
36580
  ]
@@ -45161,6 +45248,7 @@ var init_WizardContainer = __esm({
45161
45248
  init_Stack();
45162
45249
  init_Icon();
45163
45250
  init_cn();
45251
+ init_useEventBus();
45164
45252
  exports.WizardContainer = ({
45165
45253
  steps,
45166
45254
  currentStep: controlledStep,
@@ -45169,9 +45257,13 @@ var init_WizardContainer = __esm({
45169
45257
  showProgress = true,
45170
45258
  allowBack = true,
45171
45259
  compact = false,
45172
- className
45260
+ className,
45261
+ nextEvent,
45262
+ backEvent,
45263
+ completeEvent
45173
45264
  }) => {
45174
45265
  const { t } = hooks.useTranslate();
45266
+ const eventBus = useEventBus();
45175
45267
  const [internalStep, setInternalStep] = React79.useState(0);
45176
45268
  const normalizedControlledStep = (() => {
45177
45269
  if (controlledStep === void 0 || controlledStep === null)
@@ -45201,13 +45293,16 @@ var init_WizardContainer = __esm({
45201
45293
  return;
45202
45294
  }
45203
45295
  if (isLastStep) {
45296
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, { step: currentStep });
45204
45297
  onComplete?.();
45205
45298
  } else {
45299
+ if (nextEvent) eventBus.emit(`UI:${nextEvent}`, { step: currentStep + 1 });
45206
45300
  goToStep(currentStep + 1);
45207
45301
  }
45208
45302
  };
45209
45303
  const handleBack = () => {
45210
45304
  if (!isFirstStep && allowBack) {
45305
+ if (backEvent) eventBus.emit(`UI:${backEvent}`, { step: currentStep - 1 });
45211
45306
  goToStep(currentStep - 1);
45212
45307
  }
45213
45308
  };
@@ -47892,14 +47987,18 @@ var init_DrawerSlot = __esm({
47892
47987
  title: overrideTitle,
47893
47988
  position = "right",
47894
47989
  size = "md",
47895
- className
47990
+ className,
47991
+ sourceTrait
47896
47992
  }) => {
47897
47993
  const eventBus = useEventBus();
47994
+ const schemaCtx = providers.useEntitySchemaOptional();
47898
47995
  const isOpen = Boolean(children);
47899
47996
  const title = overrideTitle || extractTitle(children);
47900
47997
  const handleClose = () => {
47901
- eventBus.emit("UI:CLOSE");
47902
- eventBus.emit("UI:CANCEL");
47998
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
47999
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
48000
+ eventBus.emit(`${prefix}CLOSE`);
48001
+ eventBus.emit(`${prefix}CANCEL`);
47903
48002
  };
47904
48003
  if (!isOpen) return null;
47905
48004
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -49870,14 +49969,18 @@ var init_ModalSlot = __esm({
49870
49969
  children,
49871
49970
  title: overrideTitle,
49872
49971
  size = "md",
49873
- className
49972
+ className,
49973
+ sourceTrait
49874
49974
  }) => {
49875
49975
  const eventBus = useEventBus();
49976
+ const schemaCtx = providers.useEntitySchemaOptional();
49876
49977
  const isOpen = Boolean(children);
49877
49978
  const title = overrideTitle || extractTitle2(children);
49878
49979
  const handleClose = () => {
49879
- eventBus.emit("UI:CLOSE");
49880
- eventBus.emit("UI:CANCEL");
49980
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
49981
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
49982
+ eventBus.emit(`${prefix}CLOSE`);
49983
+ eventBus.emit(`${prefix}CANCEL`);
49881
49984
  };
49882
49985
  if (!isOpen) return null;
49883
49986
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -53442,17 +53545,21 @@ var init_ToastSlot = __esm({
53442
53545
  variant: overrideVariant,
53443
53546
  title: overrideTitle,
53444
53547
  duration = 5e3,
53445
- className
53548
+ className,
53549
+ sourceTrait
53446
53550
  }) => {
53447
53551
  const eventBus = useEventBus();
53552
+ const schemaCtx = providers.useEntitySchemaOptional();
53448
53553
  const isVisible = Boolean(children);
53449
53554
  const extracted = extractToastProps(children);
53450
53555
  const variant = overrideVariant || extracted.variant || "info";
53451
53556
  const title = overrideTitle || extracted.title;
53452
53557
  const message = extracted.message || (typeof children === "string" ? children : "");
53453
53558
  const handleDismiss = () => {
53454
- eventBus.emit("UI:DISMISS");
53455
- eventBus.emit("UI:CLOSE");
53559
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
53560
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
53561
+ eventBus.emit(`${prefix}DISMISS`);
53562
+ eventBus.emit(`${prefix}CLOSE`);
53456
53563
  };
53457
53564
  if (!isVisible) return null;
53458
53565
  const isCustomContent = React79__namespace.default.isValidElement(children) && !message;
@@ -54179,7 +54286,7 @@ function getSlotFallback(slot, config) {
54179
54286
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
54180
54287
  return /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { variant });
54181
54288
  }
54182
- function getComponentForPattern3(patternType) {
54289
+ function getComponentForPattern(patternType) {
54183
54290
  const mapping = patterns.getComponentForPattern(patternType);
54184
54291
  if (!mapping) {
54185
54292
  return null;
@@ -54388,6 +54495,7 @@ function UISlotComponent({
54388
54495
  const { t } = hooks.useTranslate();
54389
54496
  const suspenseConfig = React79.useContext(SuspenseConfigContext);
54390
54497
  const contained = React79.useContext(SlotContainedContext);
54498
+ const schemaCtx = providers.useEntitySchemaOptional();
54391
54499
  const content = slots[slot];
54392
54500
  if (children !== void 0) {
54393
54501
  if (pattern === "clear") {
@@ -54433,8 +54541,11 @@ function UISlotComponent({
54433
54541
  }
54434
54542
  const handleDismiss = () => {
54435
54543
  if (slot === "modal" || slot === "drawer") {
54436
- eventBus.emit("UI:CLOSE");
54437
- eventBus.emit("UI:CANCEL");
54544
+ const trait = content?.sourceTrait;
54545
+ const orbital = trait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(trait) : void 0;
54546
+ const prefix = orbital !== void 0 && trait !== void 0 ? `UI:${orbital}.${trait}.` : "UI:";
54547
+ eventBus.emit(`${prefix}CLOSE`);
54548
+ eventBus.emit(`${prefix}CANCEL`);
54438
54549
  }
54439
54550
  clear(slot);
54440
54551
  };
@@ -54488,6 +54599,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54488
54599
  const slotsBus = context.useUISlots();
54489
54600
  const eventBus = useEventBus();
54490
54601
  const { t } = hooks.useTranslate();
54602
+ const compiledPortalSchemaCtx = providers.useEntitySchemaOptional();
54491
54603
  React79.useEffect(() => {
54492
54604
  setPortalRoot(getOrCreatePortalRoot());
54493
54605
  }, []);
@@ -54496,8 +54608,10 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54496
54608
  });
54497
54609
  const handleDismiss = () => {
54498
54610
  if (slot === "modal" || slot === "drawer") {
54499
- eventBus.emit("UI:CLOSE");
54500
- eventBus.emit("UI:CANCEL");
54611
+ const orbital = sourceTrait !== void 0 && compiledPortalSchemaCtx !== null ? compiledPortalSchemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
54612
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
54613
+ eventBus.emit(`${prefix}CLOSE`);
54614
+ eventBus.emit(`${prefix}CANCEL`);
54501
54615
  }
54502
54616
  slotsBus.clear(slot);
54503
54617
  };
@@ -54809,7 +54923,7 @@ function SlotContentRenderer({
54809
54923
  }
54810
54924
  }
54811
54925
  const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
54812
- const PatternComponent = getComponentForPattern3(content.pattern);
54926
+ const PatternComponent = getComponentForPattern(content.pattern);
54813
54927
  if (PatternComponent) {
54814
54928
  const childrenConfig = content.props.children;
54815
54929
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -55056,6 +55170,7 @@ var init_UISlotRenderer = __esm({
55056
55170
  "custom",
55057
55171
  "dashboard-layout",
55058
55172
  "game-shell",
55173
+ "game-template",
55059
55174
  "scaled-diagram",
55060
55175
  "master-detail",
55061
55176
  "form-field",
@@ -55095,7 +55210,7 @@ function TraitFrame({
55095
55210
  if (!content) {
55096
55211
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
55097
55212
  }
55098
- const SlotContentRenderer2 = getSlotContentRenderer3();
55213
+ const SlotContentRenderer2 = getSlotContentRenderer();
55099
55214
  const rendered = /* @__PURE__ */ jsxRuntime.jsx(
55100
55215
  SlotContentRenderer2,
55101
55216
  {
@@ -55109,7 +55224,7 @@ function TraitFrame({
55109
55224
  }
55110
55225
  return /* @__PURE__ */ jsxRuntime.jsx(providers.TraitScopeProvider, { orbital, trait: traitName, children: rendered });
55111
55226
  }
55112
- function getSlotContentRenderer3() {
55227
+ function getSlotContentRenderer() {
55113
55228
  if (_slotContentRenderer) return _slotContentRenderer;
55114
55229
  const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
55115
55230
  _slotContentRenderer = mod.SlotContentRenderer;