@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 @@ 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;
@@ -7936,8 +7936,10 @@ function ActionButton({
7936
7936
  size = "md",
7937
7937
  variant = "primary",
7938
7938
  onClick,
7939
+ action,
7939
7940
  className
7940
7941
  }) {
7942
+ const eventBus = useEventBus();
7941
7943
  const sizes = sizeMap[size];
7942
7944
  const onCooldown = cooldown > 0;
7943
7945
  const isDisabled = disabled || onCooldown;
@@ -7947,7 +7949,10 @@ function ActionButton({
7947
7949
  {
7948
7950
  type: "button",
7949
7951
  disabled: isDisabled,
7950
- onClick,
7952
+ onClick: (e) => {
7953
+ if (action) eventBus.emit(`UI:${action}`, {});
7954
+ onClick?.();
7955
+ },
7951
7956
  className: cn(
7952
7957
  "relative inline-flex items-center gap-1.5 rounded-interactive border font-medium overflow-hidden transition-colors duration-150",
7953
7958
  sizes.button,
@@ -8004,6 +8009,7 @@ var init_ActionButton = __esm({
8004
8009
  "components/game/2d/atoms/ActionButton.tsx"() {
8005
8010
  init_cn();
8006
8011
  init_Icon();
8012
+ init_useEventBus();
8007
8013
  sizeMap = {
8008
8014
  sm: { button: "h-button-sm px-3 text-xs", hotkey: "text-[9px] px-1", icon: "text-xs" },
8009
8015
  md: { button: "h-button-md px-4 text-sm", hotkey: "text-xs px-1.5", icon: "text-sm" },
@@ -8057,7 +8063,7 @@ function ActionTile({
8057
8063
  draggable: !disabled,
8058
8064
  onDragStart: handleDragStart,
8059
8065
  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" }),
8066
+ 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
8067
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn(config.text, "text-foreground font-medium whitespace-nowrap"), children: action.name })
8062
8068
  ]
8063
8069
  }
@@ -8661,9 +8667,26 @@ function MiniMap({
8661
8667
  mapWidth = 100,
8662
8668
  mapHeight = 100,
8663
8669
  viewportRect = DEFAULT_VIEWPORT,
8664
- className
8670
+ className,
8671
+ tileAssets,
8672
+ unitAssets
8665
8673
  }) {
8666
8674
  const canvasRef = React79.useRef(null);
8675
+ const imgCacheRef = React79.useRef(/* @__PURE__ */ new Map());
8676
+ function loadImg(url) {
8677
+ const cached = imgCacheRef.current.get(url);
8678
+ if (cached) return cached.complete ? cached : null;
8679
+ const img = new Image();
8680
+ img.src = url;
8681
+ img.onload = () => {
8682
+ const canvas = canvasRef.current;
8683
+ if (!canvas) return;
8684
+ const ctx = canvas.getContext("2d");
8685
+ if (ctx) ctx.clearRect(0, 0, 0, 0);
8686
+ };
8687
+ imgCacheRef.current.set(url, img);
8688
+ return null;
8689
+ }
8667
8690
  React79.useEffect(() => {
8668
8691
  const canvas = canvasRef.current;
8669
8692
  if (!canvas) return;
@@ -8675,20 +8698,31 @@ function MiniMap({
8675
8698
  ctx.fillStyle = "#111";
8676
8699
  ctx.fillRect(0, 0, width, height);
8677
8700
  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
- );
8701
+ const tileAsset = tileAssets?.[tile.color] ?? tileAssets?.["default"];
8702
+ const tileImg = tileAsset ? loadImg(tileAsset.url) : null;
8703
+ const tx = Math.floor(tile.x * scaleX2);
8704
+ const ty = Math.floor(tile.y * scaleY2);
8705
+ const tw = Math.max(1, Math.ceil(scaleX2));
8706
+ const th = Math.max(1, Math.ceil(scaleY2));
8707
+ if (tileImg) {
8708
+ ctx.drawImage(tileImg, tx, ty, tw, th);
8709
+ } else {
8710
+ ctx.fillStyle = tile.color;
8711
+ ctx.fillRect(tx, ty, tw, th);
8712
+ }
8685
8713
  }
8686
8714
  for (const unit of units) {
8687
8715
  if (unit.isPlayer) continue;
8688
- ctx.fillStyle = unit.color;
8716
+ const unitAsset = unitAssets?.[unit.color] ?? unitAssets?.["default"];
8717
+ const unitImg = unitAsset ? loadImg(unitAsset.url) : null;
8689
8718
  const ux = Math.floor(unit.x * scaleX2) - 1;
8690
8719
  const uy = Math.floor(unit.y * scaleY2) - 1;
8691
- ctx.fillRect(ux, uy, 3, 3);
8720
+ if (unitImg) {
8721
+ ctx.drawImage(unitImg, ux, uy, 5, 5);
8722
+ } else {
8723
+ ctx.fillStyle = unit.color;
8724
+ ctx.fillRect(ux, uy, 3, 3);
8725
+ }
8692
8726
  }
8693
8727
  if (viewportRect) {
8694
8728
  ctx.strokeStyle = "#ffffff";
@@ -8700,7 +8734,7 @@ function MiniMap({
8700
8734
  Math.floor(viewportRect.h * scaleY2)
8701
8735
  );
8702
8736
  }
8703
- }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect]);
8737
+ }, [tiles, units, width, height, mapWidth, mapHeight, viewportRect, tileAssets, unitAssets]);
8704
8738
  const scaleX = width / mapWidth;
8705
8739
  const scaleY = height / mapHeight;
8706
8740
  const playerUnit = units.find((u) => u.isPlayer);
@@ -8777,7 +8811,9 @@ function HealthBar({
8777
8811
  labelSuffix,
8778
8812
  size = "md",
8779
8813
  className,
8780
- animated = true
8814
+ animated = true,
8815
+ frameAsset,
8816
+ fillAsset
8781
8817
  }) {
8782
8818
  const sizes = sizeMap2[size];
8783
8819
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
@@ -8796,20 +8832,25 @@ function HealthBar({
8796
8832
  "div",
8797
8833
  {
8798
8834
  className: cn(
8799
- "relative overflow-hidden rounded-full bg-muted",
8835
+ "relative overflow-hidden rounded-full",
8836
+ !frameAsset && "bg-muted",
8800
8837
  sizes.bar,
8801
8838
  "w-24",
8802
8839
  className
8803
8840
  ),
8841
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8804
8842
  children: /* @__PURE__ */ jsx(
8805
8843
  "div",
8806
8844
  {
8807
8845
  className: cn(
8808
8846
  "absolute inset-y-0 left-0 rounded-full",
8809
- percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error",
8847
+ !fillAsset && (percentage > 66 ? "bg-success" : percentage > 33 ? "bg-warning" : "bg-error"),
8810
8848
  animated && "transition-all duration-300"
8811
8849
  ),
8812
- style: { width: `${percentage}%` }
8850
+ style: {
8851
+ width: `${percentage}%`,
8852
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8853
+ }
8813
8854
  }
8814
8855
  )
8815
8856
  }
@@ -8836,18 +8877,23 @@ function HealthBar({
8836
8877
  "div",
8837
8878
  {
8838
8879
  className: cn(
8839
- "relative w-full overflow-hidden rounded-full bg-muted border border-muted",
8880
+ "relative w-full overflow-hidden rounded-full",
8881
+ !frameAsset && "bg-muted border border-muted",
8840
8882
  sizes.bar
8841
8883
  ),
8884
+ style: frameAsset ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%" } : void 0,
8842
8885
  children: /* @__PURE__ */ jsx(
8843
8886
  "div",
8844
8887
  {
8845
8888
  className: cn(
8846
8889
  "absolute inset-y-0 left-0 rounded-full",
8847
- "bg-gradient-to-r from-accent to-info",
8890
+ !fillAsset && "bg-gradient-to-r from-accent to-info",
8848
8891
  animated && "transition-all duration-500 ease-out"
8849
8892
  ),
8850
- style: { width: `${percentage}%` }
8893
+ style: {
8894
+ width: `${percentage}%`,
8895
+ ...fillAsset ? { backgroundImage: `url(${fillAsset.url})`, backgroundSize: "auto 100%" } : {}
8896
+ }
8851
8897
  }
8852
8898
  )
8853
8899
  }
@@ -12629,9 +12675,9 @@ var init_BiologyCanvas = __esm({
12629
12675
  }
12630
12676
  });
12631
12677
 
12632
- // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
12678
+ // node_modules/katex/dist/katex.min.css
12633
12679
  var init_katex_min = __esm({
12634
- "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
12680
+ "node_modules/katex/dist/katex.min.css"() {
12635
12681
  }
12636
12682
  });
12637
12683
  var Tabs;
@@ -21438,14 +21484,19 @@ function ChoiceButton({
21438
21484
  disabled = false,
21439
21485
  selected = false,
21440
21486
  onClick,
21487
+ action,
21441
21488
  className
21442
21489
  }) {
21490
+ const eventBus = useEventBus();
21443
21491
  return /* @__PURE__ */ jsxs(
21444
21492
  "button",
21445
21493
  {
21446
21494
  type: "button",
21447
21495
  disabled,
21448
- onClick,
21496
+ onClick: (e) => {
21497
+ if (action) eventBus.emit(`UI:${action}`, {});
21498
+ onClick?.();
21499
+ },
21449
21500
  className: cn(
21450
21501
  "w-full text-left px-4 py-2.5 rounded-interactive border transition-all duration-150",
21451
21502
  "flex items-center gap-2",
@@ -21493,6 +21544,7 @@ var init_ChoiceButton = __esm({
21493
21544
  "components/game/2d/atoms/ChoiceButton.tsx"() {
21494
21545
  init_cn();
21495
21546
  init_Icon();
21547
+ init_useEventBus();
21496
21548
  ChoiceButton.displayName = "ChoiceButton";
21497
21549
  }
21498
21550
  });
@@ -22538,6 +22590,7 @@ function ControlGrid({
22538
22590
  actionEvent,
22539
22591
  onDirection,
22540
22592
  directionEvent,
22593
+ directionAssets,
22541
22594
  size = "md",
22542
22595
  disabled,
22543
22596
  className
@@ -22577,7 +22630,8 @@ function ControlGrid({
22577
22630
  const dir = (d) => /* @__PURE__ */ jsx(
22578
22631
  ControlButton,
22579
22632
  {
22580
- icon: arrowIcons[d],
22633
+ icon: directionAssets?.[d] ? void 0 : arrowIcons[d],
22634
+ assetUrl: directionAssets?.[d],
22581
22635
  size: sizeKey[size],
22582
22636
  variant: "secondary",
22583
22637
  pressed: active.has(d),
@@ -22718,6 +22772,8 @@ function CounterMinimal({
22718
22772
  size = "md",
22719
22773
  onDecrement,
22720
22774
  onIncrement,
22775
+ decrementEvent,
22776
+ incrementEvent,
22721
22777
  className
22722
22778
  }) {
22723
22779
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22728,6 +22784,7 @@ function CounterMinimal({
22728
22784
  {
22729
22785
  variant: "secondary",
22730
22786
  size: sizeStyles8[size].button,
22787
+ action: decrementEvent,
22731
22788
  onClick: onDecrement,
22732
22789
  disabled: resolved.decrementDisabled,
22733
22790
  icon: "minus",
@@ -22750,6 +22807,7 @@ function CounterMinimal({
22750
22807
  {
22751
22808
  variant: "secondary",
22752
22809
  size: sizeStyles8[size].button,
22810
+ action: incrementEvent,
22753
22811
  onClick: onIncrement,
22754
22812
  disabled: resolved.incrementDisabled,
22755
22813
  icon: "plus",
@@ -22766,6 +22824,9 @@ function CounterStandard({
22766
22824
  onDecrement,
22767
22825
  onIncrement,
22768
22826
  onReset,
22827
+ decrementEvent,
22828
+ incrementEvent,
22829
+ resetEvent,
22769
22830
  className
22770
22831
  }) {
22771
22832
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22796,6 +22857,7 @@ function CounterStandard({
22796
22857
  {
22797
22858
  variant: "secondary",
22798
22859
  size: sizeStyles8[size].button,
22860
+ action: decrementEvent,
22799
22861
  onClick: onDecrement,
22800
22862
  disabled: resolved.decrementDisabled,
22801
22863
  icon: "minus"
@@ -22806,6 +22868,7 @@ function CounterStandard({
22806
22868
  {
22807
22869
  variant: "primary",
22808
22870
  size: sizeStyles8[size].button,
22871
+ action: incrementEvent,
22809
22872
  onClick: onIncrement,
22810
22873
  disabled: resolved.incrementDisabled,
22811
22874
  icon: "plus"
@@ -22817,6 +22880,7 @@ function CounterStandard({
22817
22880
  {
22818
22881
  variant: "ghost",
22819
22882
  size: "sm",
22883
+ action: resetEvent,
22820
22884
  onClick: onReset,
22821
22885
  icon: "rotate-ccw",
22822
22886
  children: "Reset"
@@ -22832,6 +22896,9 @@ function CounterFull({
22832
22896
  onDecrement,
22833
22897
  onIncrement,
22834
22898
  onReset,
22899
+ decrementEvent,
22900
+ incrementEvent,
22901
+ resetEvent,
22835
22902
  className
22836
22903
  }) {
22837
22904
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
@@ -22865,6 +22932,7 @@ function CounterFull({
22865
22932
  {
22866
22933
  variant: "secondary",
22867
22934
  size: sizeStyles8[size].button,
22935
+ action: decrementEvent,
22868
22936
  onClick: onDecrement,
22869
22937
  disabled: resolved.decrementDisabled,
22870
22938
  icon: "minus",
@@ -22876,6 +22944,7 @@ function CounterFull({
22876
22944
  {
22877
22945
  variant: "primary",
22878
22946
  size: sizeStyles8[size].button,
22947
+ action: incrementEvent,
22879
22948
  onClick: onIncrement,
22880
22949
  disabled: resolved.incrementDisabled,
22881
22950
  icon: "plus",
@@ -22888,6 +22957,7 @@ function CounterFull({
22888
22957
  {
22889
22958
  variant: "ghost",
22890
22959
  size: "sm",
22960
+ action: resetEvent,
22891
22961
  onClick: onReset,
22892
22962
  icon: "rotate-ccw",
22893
22963
  children: "Reset to 0"
@@ -29584,14 +29654,15 @@ function TimerDisplay({
29584
29654
  format = "mm:ss",
29585
29655
  size = "md",
29586
29656
  className,
29587
- lowThreshold
29657
+ lowThreshold,
29658
+ iconAsset
29588
29659
  }) {
29589
29660
  const isLow = lowThreshold != null && seconds <= lowThreshold && seconds > 0;
29590
- return /* @__PURE__ */ jsx(
29661
+ return /* @__PURE__ */ jsxs(
29591
29662
  "div",
29592
29663
  {
29593
29664
  className: cn(
29594
- "inline-flex items-center justify-center rounded-container",
29665
+ "inline-flex items-center gap-1 justify-center rounded-container",
29595
29666
  "bg-card/80 border border-muted font-mono font-bold tabular-nums",
29596
29667
  sizeMap9[size],
29597
29668
  running && "border-success/50",
@@ -29599,7 +29670,10 @@ function TimerDisplay({
29599
29670
  !isLow && "text-foreground",
29600
29671
  className
29601
29672
  ),
29602
- children: formatTime(seconds, format)
29673
+ children: [
29674
+ iconAsset && /* @__PURE__ */ jsx("img", { src: iconAsset.url, alt: "", className: "w-4 h-4 object-contain flex-shrink-0" }),
29675
+ formatTime(seconds, format)
29676
+ ]
29603
29677
  }
29604
29678
  );
29605
29679
  }
@@ -29695,15 +29769,20 @@ function ItemSlot({
29695
29769
  size = "md",
29696
29770
  selected,
29697
29771
  onClick,
29772
+ action,
29698
29773
  className
29699
29774
  }) {
29700
- const isClickable = onClick != null;
29775
+ const eventBus = useEventBus();
29776
+ const isClickable = onClick != null || action != null;
29701
29777
  const px = assetSizeMap[size];
29702
29778
  return /* @__PURE__ */ jsx(
29703
29779
  "button",
29704
29780
  {
29705
29781
  type: "button",
29706
- onClick,
29782
+ onClick: () => {
29783
+ if (action) eventBus.emit(`UI:${action}`, {});
29784
+ onClick?.();
29785
+ },
29707
29786
  disabled: !isClickable,
29708
29787
  title: label,
29709
29788
  className: cn(
@@ -29751,6 +29830,7 @@ var init_ItemSlot = __esm({
29751
29830
  "use client";
29752
29831
  init_cn();
29753
29832
  init_Icon();
29833
+ init_useEventBus();
29754
29834
  sizeMap11 = {
29755
29835
  sm: "w-10 h-10 text-lg",
29756
29836
  md: "w-14 h-14 text-2xl",
@@ -30177,7 +30257,7 @@ function InventoryGrid({
30177
30257
  (id) => {
30178
30258
  onSelect?.(id);
30179
30259
  if (selectEvent) {
30180
- eventBus.emit(selectEvent, { id });
30260
+ eventBus.emit(`UI:${selectEvent}`, { id });
30181
30261
  }
30182
30262
  },
30183
30263
  [onSelect, selectEvent, eventBus]
@@ -30382,27 +30462,21 @@ function GameMenu({
30382
30462
  options,
30383
30463
  menuItems,
30384
30464
  onSelect,
30385
- eventBus: eventBusProp,
30386
30465
  background,
30387
- logo = "",
30466
+ logo,
30388
30467
  className
30389
30468
  }) {
30390
30469
  const resolvedOptions = options ?? menuItems ?? DEFAULT_MENU_OPTIONS;
30391
- let eventBusFromHook = null;
30392
- try {
30393
- eventBusFromHook = useEventBus();
30394
- } catch {
30395
- }
30396
- const eventBus = eventBusProp || eventBusFromHook;
30470
+ const eventBus = useEventBus();
30397
30471
  const handleOptionClick = React79.useCallback(
30398
30472
  (option) => {
30399
- if (option.event && eventBus) {
30473
+ if (option.event) {
30400
30474
  eventBus.emit(`UI:${option.event}`, { option });
30401
30475
  }
30402
30476
  if (onSelect) {
30403
30477
  onSelect(option);
30404
30478
  }
30405
- if (option.navigatesTo && eventBus) {
30479
+ if (option.navigatesTo) {
30406
30480
  eventBus.emit("UI:NAVIGATE", { url: option.navigatesTo, option });
30407
30481
  }
30408
30482
  },
@@ -30423,7 +30497,7 @@ function GameMenu({
30423
30497
  logo && /* @__PURE__ */ jsx(
30424
30498
  "img",
30425
30499
  {
30426
- src: logo,
30500
+ src: logo.url,
30427
30501
  alt: title,
30428
30502
  className: "h-24 w-auto mx-auto mb-6 drop-shadow-2xl"
30429
30503
  }
@@ -30883,7 +30957,9 @@ var init_GameAudioProvider = __esm({
30883
30957
  });
30884
30958
  function GameAudioToggle({
30885
30959
  size = "sm",
30886
- className
30960
+ className,
30961
+ onAsset,
30962
+ offAsset
30887
30963
  }) {
30888
30964
  const ctx = useGameAudioContextOptional();
30889
30965
  const [localMuted, setLocalMuted] = useState(false);
@@ -30892,6 +30968,7 @@ function GameAudioToggle({
30892
30968
  const handleToggle = useCallback(() => {
30893
30969
  setMuted(!muted);
30894
30970
  }, [muted, setMuted]);
30971
+ const activeAsset = muted ? offAsset : onAsset;
30895
30972
  return /* @__PURE__ */ jsx(
30896
30973
  Button,
30897
30974
  {
@@ -30900,7 +30977,7 @@ function GameAudioToggle({
30900
30977
  onClick: handleToggle,
30901
30978
  className: cn("text-lg leading-none px-2", className),
30902
30979
  "aria-pressed": muted,
30903
- children: muted ? "\u{1F507}" : "\u{1F50A}"
30980
+ children: activeAsset ? /* @__PURE__ */ jsx("img", { src: activeAsset.url, alt: muted ? "Muted" : "Sound on", className: "w-5 h-5 object-contain" }) : muted ? "\u{1F507}" : "\u{1F50A}"
30904
30981
  }
30905
30982
  );
30906
30983
  }
@@ -31489,6 +31566,7 @@ function PlatformerBoard({
31489
31566
  canvasHeight: _canvasHeight = 400,
31490
31567
  playerSprite,
31491
31568
  tileSprites,
31569
+ ui: _ui,
31492
31570
  bgColor: _bgColor,
31493
31571
  keyEvent = "KEY",
31494
31572
  playAgainEvent = "PLAY_AGAIN",
@@ -32913,6 +32991,7 @@ function TanksBoard({
32913
32991
  features,
32914
32992
  assetManifest,
32915
32993
  assetBaseUrl,
32994
+ ui: _ui,
32916
32995
  scale = 0.45,
32917
32996
  showMinimap = true,
32918
32997
  enableCamera = true,
@@ -33620,7 +33699,7 @@ function TraitSlot({
33620
33699
  size = "md",
33621
33700
  showTooltip = true,
33622
33701
  categoryColors,
33623
- tooltipFrameUrl = "",
33702
+ tooltipFrameUrl,
33624
33703
  className,
33625
33704
  feedback,
33626
33705
  onItemDrop,
@@ -33750,7 +33829,7 @@ function TraitSlot({
33750
33829
  as: "img",
33751
33830
  className: "object-contain",
33752
33831
  style: { width: config.icon, height: config.icon },
33753
- ...{ src: equippedItem.iconUrl, alt: equippedItem.name }
33832
+ ...{ src: equippedItem.iconUrl.url, alt: equippedItem.name }
33754
33833
  }
33755
33834
  ) : /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-center leading-none", style: { fontSize: config.icon }, children: equippedItem.iconEmoji || "\u2726" }),
33756
33835
  (onRemove || removeEvent) && /* @__PURE__ */ jsx(
@@ -33779,7 +33858,7 @@ function TraitSlot({
33779
33858
  ...getTooltipStyle(),
33780
33859
  minWidth: 200,
33781
33860
  ...tooltipFrameUrl ? {
33782
- borderImage: `url(${tooltipFrameUrl}) 60 fill / 15px / 0 stretch`,
33861
+ borderImage: `url(${tooltipFrameUrl.url}) 60 fill / 15px / 0 stretch`,
33783
33862
  border: "none"
33784
33863
  } : {}
33785
33864
  },
@@ -34076,6 +34155,42 @@ function computeSlotFeedback(playerSeq, solutions) {
34076
34155
  (id, i) => id !== void 0 && id === bestSolution[i] ? "correct" : "wrong"
34077
34156
  );
34078
34157
  }
34158
+ function isFieldRecord(v) {
34159
+ return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Date);
34160
+ }
34161
+ function assetFromField(v) {
34162
+ if (!isFieldRecord(v)) return void 0;
34163
+ const url = typeof v.url === "string" ? v.url : void 0;
34164
+ const role = typeof v.role === "string" ? v.role : void 0;
34165
+ const category = typeof v.category === "string" ? v.category : "";
34166
+ if (!url || !role) return void 0;
34167
+ return {
34168
+ url,
34169
+ role,
34170
+ category,
34171
+ name: typeof v.name === "string" ? v.name : void 0,
34172
+ thumbnailUrl: typeof v.thumbnailUrl === "string" ? v.thumbnailUrl : void 0,
34173
+ style: typeof v.style === "string" ? v.style : void 0,
34174
+ variant: typeof v.variant === "string" ? v.variant : void 0,
34175
+ dimension: typeof v.dimension === "string" ? v.dimension : void 0,
34176
+ aspect: typeof v.aspect === "string" ? v.aspect : void 0
34177
+ };
34178
+ }
34179
+ function slotItemFromField(fv) {
34180
+ if (!isFieldRecord(fv)) return void 0;
34181
+ const id = typeof fv.id === "string" ? fv.id : void 0;
34182
+ const name = typeof fv.name === "string" ? fv.name : void 0;
34183
+ const category = typeof fv.category === "string" ? fv.category : void 0;
34184
+ if (!id || !name || !category) return void 0;
34185
+ return {
34186
+ id,
34187
+ name,
34188
+ category,
34189
+ description: typeof fv.description === "string" ? fv.description : void 0,
34190
+ iconEmoji: typeof fv.iconEmoji === "string" ? fv.iconEmoji : void 0,
34191
+ iconUrl: assetFromField(fv.iconUrl)
34192
+ };
34193
+ }
34079
34194
  function SequencerBoard({
34080
34195
  entity,
34081
34196
  categoryColors,
@@ -34086,6 +34201,7 @@ function SequencerBoard({
34086
34201
  removeEvent,
34087
34202
  checkEvent,
34088
34203
  playAgainEvent,
34204
+ stepEvent,
34089
34205
  className
34090
34206
  }) {
34091
34207
  const { emit } = useEventBus();
@@ -34093,7 +34209,11 @@ function SequencerBoard({
34093
34209
  const resolved = boardEntity(entity);
34094
34210
  const maxSlots = num(resolved?.maxSlots) || 3;
34095
34211
  const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
34096
- const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
34212
+ const availableActions = (Array.isArray(resolved?.availableActions) ? resolved.availableActions : []).reduce((acc, fv) => {
34213
+ const item = slotItemFromField(fv);
34214
+ if (item) acc.push(item);
34215
+ return acc;
34216
+ }, []);
34097
34217
  const allowDuplicates = resolved?.allowDuplicates !== false;
34098
34218
  const entitySlots = Array.isArray(resolved?.slots) ? resolved.slots : [];
34099
34219
  const entityResult = str(resolved?.result);
@@ -34151,7 +34271,7 @@ function SequencerBoard({
34151
34271
  let step = 0;
34152
34272
  const advance = () => {
34153
34273
  step++;
34154
- emit("UI:STEP", { step });
34274
+ if (stepEvent) emit(`UI:${stepEvent}`, { step });
34155
34275
  if (step >= maxSlots) {
34156
34276
  if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
34157
34277
  const playerSeq = slots.map((s) => s?.id);
@@ -36050,24 +36170,55 @@ function SimulationControls({
36050
36170
  onReset,
36051
36171
  onSpeedChange,
36052
36172
  onParameterChange,
36173
+ playEvent,
36174
+ pauseEvent,
36175
+ stepEvent,
36176
+ resetEvent,
36177
+ speedChangeEvent,
36178
+ parameterChangeEvent,
36053
36179
  assetManifest,
36054
36180
  className
36055
36181
  }) {
36182
+ const eventBus = useEventBus();
36056
36183
  const ui = assetManifest?.ui;
36184
+ const handlePlay = () => {
36185
+ if (playEvent) eventBus.emit(`UI:${playEvent}`, {});
36186
+ onPlay?.();
36187
+ };
36188
+ const handlePause = () => {
36189
+ if (pauseEvent) eventBus.emit(`UI:${pauseEvent}`, {});
36190
+ onPause?.();
36191
+ };
36192
+ const handleStep = () => {
36193
+ if (stepEvent) eventBus.emit(`UI:${stepEvent}`, {});
36194
+ onStep?.();
36195
+ };
36196
+ const handleReset = () => {
36197
+ if (resetEvent) eventBus.emit(`UI:${resetEvent}`, {});
36198
+ onReset?.();
36199
+ };
36200
+ const handleSpeedChange = (s) => {
36201
+ if (speedChangeEvent) eventBus.emit(`UI:${speedChangeEvent}`, { speed: s });
36202
+ onSpeedChange?.(s);
36203
+ };
36204
+ const handleParameterChange = (name, value) => {
36205
+ if (parameterChangeEvent) eventBus.emit(`UI:${parameterChangeEvent}`, { name, value });
36206
+ onParameterChange?.(name, value);
36207
+ };
36057
36208
  return /* @__PURE__ */ jsxs(VStack, { gap: "md", className, children: [
36058
36209
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", children: [
36059
- running ? /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "secondary", onClick: onPause, children: [
36210
+ running ? /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "secondary", onClick: handlePause, children: [
36060
36211
  /* @__PURE__ */ jsx(GameIcon, { icon: Pause, assetUrl: ui?.["pause"], size: "sm" }),
36061
36212
  "Pause"
36062
- ] }) : /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "primary", onClick: onPlay, children: [
36213
+ ] }) : /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "primary", onClick: handlePlay, children: [
36063
36214
  /* @__PURE__ */ jsx(GameIcon, { icon: Play, assetUrl: ui?.["play"], size: "sm" }),
36064
36215
  "Play"
36065
36216
  ] }),
36066
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: onStep, disabled: running, children: [
36217
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: handleStep, disabled: running, children: [
36067
36218
  /* @__PURE__ */ jsx(GameIcon, { icon: SkipForward, assetUrl: ui?.["step"], size: "sm" }),
36068
36219
  "Step"
36069
36220
  ] }),
36070
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: onReset, children: [
36221
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: handleReset, children: [
36071
36222
  /* @__PURE__ */ jsx(GameIcon, { icon: RotateCcw, assetUrl: ui?.["reset"], size: "sm" }),
36072
36223
  "Reset"
36073
36224
  ] })
@@ -36086,7 +36237,7 @@ function SimulationControls({
36086
36237
  max: 5,
36087
36238
  step: 0.1,
36088
36239
  value: speed,
36089
- onChange: (e) => onSpeedChange(parseFloat(e.target.value)),
36240
+ onChange: (e) => handleSpeedChange(parseFloat(e.target.value)),
36090
36241
  className: "w-full"
36091
36242
  }
36092
36243
  )
@@ -36105,7 +36256,7 @@ function SimulationControls({
36105
36256
  max: param.max,
36106
36257
  step: param.step,
36107
36258
  value: param.value,
36108
- onChange: (e) => onParameterChange(name, parseFloat(e.target.value)),
36259
+ onChange: (e) => handleParameterChange(name, parseFloat(e.target.value)),
36109
36260
  className: "w-full"
36110
36261
  }
36111
36262
  )
@@ -36114,6 +36265,7 @@ function SimulationControls({
36114
36265
  }
36115
36266
  var init_SimulationControls = __esm({
36116
36267
  "components/game/2d/organisms/SimulationControls.tsx"() {
36268
+ init_useEventBus();
36117
36269
  init_atoms();
36118
36270
  init_GameIcon();
36119
36271
  SimulationControls.displayName = "SimulationControls";
@@ -36182,35 +36334,7 @@ var init_SimulationGraph = __esm({
36182
36334
  SimulationGraph.displayName = "SimulationGraph";
36183
36335
  }
36184
36336
  });
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;
36337
+ var GameTemplate;
36214
36338
  var init_GameTemplate = __esm({
36215
36339
  "components/game/2d/templates/GameTemplate.tsx"() {
36216
36340
  init_cn();
@@ -36218,7 +36342,6 @@ var init_GameTemplate = __esm({
36218
36342
  init_Stack();
36219
36343
  init_Typography();
36220
36344
  init_Button();
36221
- _scr = null;
36222
36345
  GameTemplate = ({
36223
36346
  entity,
36224
36347
  title = "Game",
@@ -36227,7 +36350,8 @@ var init_GameTemplate = __esm({
36227
36350
  debugPanel,
36228
36351
  showDebugPanel = false,
36229
36352
  controls,
36230
- className
36353
+ className,
36354
+ backgroundAsset
36231
36355
  }) => {
36232
36356
  return /* @__PURE__ */ jsxs(
36233
36357
  Box,
@@ -36284,15 +36408,16 @@ var init_GameTemplate = __esm({
36284
36408
  {
36285
36409
  position: "relative",
36286
36410
  fullWidth: true,
36287
- className: "flex-1 bg-muted",
36411
+ className: backgroundAsset ? "flex-1" : "flex-1 bg-muted",
36412
+ style: backgroundAsset ? { backgroundImage: `url(${backgroundAsset.url})`, backgroundSize: "cover", backgroundPosition: "center" } : void 0,
36288
36413
  children: [
36289
- resolveDescriptor(children, "gt-children"),
36414
+ children,
36290
36415
  hud && /* @__PURE__ */ jsx(
36291
36416
  Box,
36292
36417
  {
36293
36418
  position: "absolute",
36294
36419
  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") })
36420
+ children: /* @__PURE__ */ jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
36296
36421
  }
36297
36422
  )
36298
36423
  ]
@@ -36317,7 +36442,7 @@ var init_GameTemplate = __esm({
36317
36442
  children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Debug Panel" })
36318
36443
  }
36319
36444
  ),
36320
- /* @__PURE__ */ jsx(Box, { padding: "md", children: resolveDescriptor(debugPanel, "gt-debug") })
36445
+ /* @__PURE__ */ jsx(Box, { padding: "md", children: debugPanel })
36321
36446
  ]
36322
36447
  }
36323
36448
  )
@@ -36328,59 +36453,21 @@ var init_GameTemplate = __esm({
36328
36453
  GameTemplate.displayName = "GameTemplate";
36329
36454
  }
36330
36455
  });
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;
36456
+ var GameShell;
36371
36457
  var init_GameShell = __esm({
36372
36458
  "components/game/2d/templates/GameShell.tsx"() {
36373
36459
  init_cn();
36374
36460
  init_Box();
36375
36461
  init_Stack();
36376
36462
  init_Typography();
36377
- _scr2 = null;
36378
36463
  GameShell = ({
36379
36464
  appName = "Game",
36380
36465
  hud,
36381
36466
  className,
36382
36467
  showTopBar = true,
36383
- children
36468
+ children,
36469
+ backgroundAsset,
36470
+ hudBackgroundAsset
36384
36471
  }) => {
36385
36472
  return /* @__PURE__ */ jsxs(
36386
36473
  Box,
@@ -36395,7 +36482,7 @@ var init_GameShell = __esm({
36395
36482
  width: "100vw",
36396
36483
  height: "100vh",
36397
36484
  overflow: "hidden",
36398
- background: "var(--color-background, #0a0a0f)",
36485
+ background: backgroundAsset ? `url(${backgroundAsset.url}) center/cover no-repeat` : "var(--color-background, #0a0a0f)",
36399
36486
  color: "var(--color-text, #e0e0e0)"
36400
36487
  },
36401
36488
  children: [
@@ -36405,7 +36492,7 @@ var init_GameShell = __esm({
36405
36492
  className: "game-shell__header",
36406
36493
  style: {
36407
36494
  flexShrink: 0,
36408
- background: "var(--color-surface, #12121f)",
36495
+ background: hudBackgroundAsset ? `url(${hudBackgroundAsset.url}) center/cover no-repeat` : "var(--color-surface, #12121f)",
36409
36496
  borderBottom: "1px solid var(--color-border, #2a2a3a)"
36410
36497
  },
36411
36498
  children: [
@@ -36428,7 +36515,7 @@ var init_GameShell = __esm({
36428
36515
  )
36429
36516
  }
36430
36517
  ),
36431
- hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", style: { width: "100%" }, children: resolveDescriptor2(hud, "gs-hud") })
36518
+ hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", style: { width: "100%" }, children: hud })
36432
36519
  ]
36433
36520
  }
36434
36521
  ),
@@ -36441,7 +36528,7 @@ var init_GameShell = __esm({
36441
36528
  overflow: "hidden",
36442
36529
  position: "relative"
36443
36530
  },
36444
- children: resolveDescriptor2(children, "gs-children")
36531
+ children
36445
36532
  }
36446
36533
  )
36447
36534
  ]
@@ -45115,6 +45202,7 @@ var init_WizardContainer = __esm({
45115
45202
  init_Stack();
45116
45203
  init_Icon();
45117
45204
  init_cn();
45205
+ init_useEventBus();
45118
45206
  WizardContainer = ({
45119
45207
  steps,
45120
45208
  currentStep: controlledStep,
@@ -45123,9 +45211,13 @@ var init_WizardContainer = __esm({
45123
45211
  showProgress = true,
45124
45212
  allowBack = true,
45125
45213
  compact = false,
45126
- className
45214
+ className,
45215
+ nextEvent,
45216
+ backEvent,
45217
+ completeEvent
45127
45218
  }) => {
45128
45219
  const { t } = useTranslate();
45220
+ const eventBus = useEventBus();
45129
45221
  const [internalStep, setInternalStep] = useState(0);
45130
45222
  const normalizedControlledStep = (() => {
45131
45223
  if (controlledStep === void 0 || controlledStep === null)
@@ -45155,13 +45247,16 @@ var init_WizardContainer = __esm({
45155
45247
  return;
45156
45248
  }
45157
45249
  if (isLastStep) {
45250
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, { step: currentStep });
45158
45251
  onComplete?.();
45159
45252
  } else {
45253
+ if (nextEvent) eventBus.emit(`UI:${nextEvent}`, { step: currentStep + 1 });
45160
45254
  goToStep(currentStep + 1);
45161
45255
  }
45162
45256
  };
45163
45257
  const handleBack = () => {
45164
45258
  if (!isFirstStep && allowBack) {
45259
+ if (backEvent) eventBus.emit(`UI:${backEvent}`, { step: currentStep - 1 });
45165
45260
  goToStep(currentStep - 1);
45166
45261
  }
45167
45262
  };
@@ -47846,14 +47941,18 @@ var init_DrawerSlot = __esm({
47846
47941
  title: overrideTitle,
47847
47942
  position = "right",
47848
47943
  size = "md",
47849
- className
47944
+ className,
47945
+ sourceTrait
47850
47946
  }) => {
47851
47947
  const eventBus = useEventBus();
47948
+ const schemaCtx = useEntitySchemaOptional();
47852
47949
  const isOpen = Boolean(children);
47853
47950
  const title = overrideTitle || extractTitle(children);
47854
47951
  const handleClose = () => {
47855
- eventBus.emit("UI:CLOSE");
47856
- eventBus.emit("UI:CANCEL");
47952
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
47953
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
47954
+ eventBus.emit(`${prefix}CLOSE`);
47955
+ eventBus.emit(`${prefix}CANCEL`);
47857
47956
  };
47858
47957
  if (!isOpen) return null;
47859
47958
  return /* @__PURE__ */ jsx(
@@ -49824,14 +49923,18 @@ var init_ModalSlot = __esm({
49824
49923
  children,
49825
49924
  title: overrideTitle,
49826
49925
  size = "md",
49827
- className
49926
+ className,
49927
+ sourceTrait
49828
49928
  }) => {
49829
49929
  const eventBus = useEventBus();
49930
+ const schemaCtx = useEntitySchemaOptional();
49830
49931
  const isOpen = Boolean(children);
49831
49932
  const title = overrideTitle || extractTitle2(children);
49832
49933
  const handleClose = () => {
49833
- eventBus.emit("UI:CLOSE");
49834
- eventBus.emit("UI:CANCEL");
49934
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
49935
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
49936
+ eventBus.emit(`${prefix}CLOSE`);
49937
+ eventBus.emit(`${prefix}CANCEL`);
49835
49938
  };
49836
49939
  if (!isOpen) return null;
49837
49940
  return /* @__PURE__ */ jsx(
@@ -53396,17 +53499,21 @@ var init_ToastSlot = __esm({
53396
53499
  variant: overrideVariant,
53397
53500
  title: overrideTitle,
53398
53501
  duration = 5e3,
53399
- className
53502
+ className,
53503
+ sourceTrait
53400
53504
  }) => {
53401
53505
  const eventBus = useEventBus();
53506
+ const schemaCtx = useEntitySchemaOptional();
53402
53507
  const isVisible = Boolean(children);
53403
53508
  const extracted = extractToastProps(children);
53404
53509
  const variant = overrideVariant || extracted.variant || "info";
53405
53510
  const title = overrideTitle || extracted.title;
53406
53511
  const message = extracted.message || (typeof children === "string" ? children : "");
53407
53512
  const handleDismiss = () => {
53408
- eventBus.emit("UI:DISMISS");
53409
- eventBus.emit("UI:CLOSE");
53513
+ const orbital = sourceTrait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
53514
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
53515
+ eventBus.emit(`${prefix}DISMISS`);
53516
+ eventBus.emit(`${prefix}CLOSE`);
53410
53517
  };
53411
53518
  if (!isVisible) return null;
53412
53519
  const isCustomContent = React79__default.isValidElement(children) && !message;
@@ -54133,8 +54240,8 @@ function getSlotFallback(slot, config) {
54133
54240
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
54134
54241
  return /* @__PURE__ */ jsx(Skeleton, { variant });
54135
54242
  }
54136
- function getComponentForPattern3(patternType) {
54137
- const mapping = getComponentForPattern(patternType);
54243
+ function getComponentForPattern(patternType) {
54244
+ const mapping = getComponentForPattern$1(patternType);
54138
54245
  if (!mapping) {
54139
54246
  return null;
54140
54247
  }
@@ -54342,6 +54449,7 @@ function UISlotComponent({
54342
54449
  const { t } = useTranslate();
54343
54450
  const suspenseConfig = useContext(SuspenseConfigContext);
54344
54451
  const contained = useContext(SlotContainedContext);
54452
+ const schemaCtx = useEntitySchemaOptional();
54345
54453
  const content = slots[slot];
54346
54454
  if (children !== void 0) {
54347
54455
  if (pattern === "clear") {
@@ -54387,8 +54495,11 @@ function UISlotComponent({
54387
54495
  }
54388
54496
  const handleDismiss = () => {
54389
54497
  if (slot === "modal" || slot === "drawer") {
54390
- eventBus.emit("UI:CLOSE");
54391
- eventBus.emit("UI:CANCEL");
54498
+ const trait = content?.sourceTrait;
54499
+ const orbital = trait !== void 0 && schemaCtx !== null ? schemaCtx.orbitalsByTrait.get(trait) : void 0;
54500
+ const prefix = orbital !== void 0 && trait !== void 0 ? `UI:${orbital}.${trait}.` : "UI:";
54501
+ eventBus.emit(`${prefix}CLOSE`);
54502
+ eventBus.emit(`${prefix}CANCEL`);
54392
54503
  }
54393
54504
  clear(slot);
54394
54505
  };
@@ -54442,6 +54553,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54442
54553
  const slotsBus = useUISlots();
54443
54554
  const eventBus = useEventBus();
54444
54555
  const { t } = useTranslate();
54556
+ const compiledPortalSchemaCtx = useEntitySchemaOptional();
54445
54557
  useEffect(() => {
54446
54558
  setPortalRoot(getOrCreatePortalRoot());
54447
54559
  }, []);
@@ -54450,8 +54562,10 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
54450
54562
  });
54451
54563
  const handleDismiss = () => {
54452
54564
  if (slot === "modal" || slot === "drawer") {
54453
- eventBus.emit("UI:CLOSE");
54454
- eventBus.emit("UI:CANCEL");
54565
+ const orbital = sourceTrait !== void 0 && compiledPortalSchemaCtx !== null ? compiledPortalSchemaCtx.orbitalsByTrait.get(sourceTrait) : void 0;
54566
+ const prefix = orbital !== void 0 && sourceTrait !== void 0 ? `UI:${orbital}.${sourceTrait}.` : "UI:";
54567
+ eventBus.emit(`${prefix}CLOSE`);
54568
+ eventBus.emit(`${prefix}CANCEL`);
54455
54569
  }
54456
54570
  slotsBus.clear(slot);
54457
54571
  };
@@ -54654,7 +54768,7 @@ function isPatternConfig(value) {
54654
54768
  if (value instanceof Date) return false;
54655
54769
  if (typeof value === "function") return false;
54656
54770
  const record = value;
54657
- return "type" in record && typeof record.type === "string" && getComponentForPattern(record.type) !== null;
54771
+ return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
54658
54772
  }
54659
54773
  function isPlainConfigObject(value) {
54660
54774
  if (React79__default.isValidElement(value)) return false;
@@ -54763,7 +54877,7 @@ function SlotContentRenderer({
54763
54877
  }
54764
54878
  }
54765
54879
  const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
54766
- const PatternComponent = getComponentForPattern3(content.pattern);
54880
+ const PatternComponent = getComponentForPattern(content.pattern);
54767
54881
  if (PatternComponent) {
54768
54882
  const childrenConfig = content.props.children;
54769
54883
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -55010,6 +55124,7 @@ var init_UISlotRenderer = __esm({
55010
55124
  "custom",
55011
55125
  "dashboard-layout",
55012
55126
  "game-shell",
55127
+ "game-template",
55013
55128
  "scaled-diagram",
55014
55129
  "master-detail",
55015
55130
  "form-field",
@@ -55049,7 +55164,7 @@ function TraitFrame({
55049
55164
  if (!content) {
55050
55165
  return /* @__PURE__ */ jsx(Fragment, { children: fallback });
55051
55166
  }
55052
- const SlotContentRenderer2 = getSlotContentRenderer3();
55167
+ const SlotContentRenderer2 = getSlotContentRenderer();
55053
55168
  const rendered = /* @__PURE__ */ jsx(
55054
55169
  SlotContentRenderer2,
55055
55170
  {
@@ -55063,7 +55178,7 @@ function TraitFrame({
55063
55178
  }
55064
55179
  return /* @__PURE__ */ jsx(TraitScopeProvider, { orbital, trait: traitName, children: rendered });
55065
55180
  }
55066
- function getSlotContentRenderer3() {
55181
+ function getSlotContentRenderer() {
55067
55182
  if (_slotContentRenderer) return _slotContentRenderer;
55068
55183
  const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
55069
55184
  _slotContentRenderer = mod.SlotContentRenderer;