@almadar/ui 5.64.0 → 5.67.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 (31) hide show
  1. package/dist/avl/index.cjs +241 -71
  2. package/dist/avl/index.d.cts +10 -2
  3. package/dist/avl/index.d.ts +1 -0
  4. package/dist/avl/index.js +244 -75
  5. package/dist/components/avl/derive-edit-focus.d.ts +8 -0
  6. package/dist/components/core/organisms/ChatBar.d.ts +31 -0
  7. package/dist/components/core/organisms/SubagentTracePanel.d.ts +50 -0
  8. package/dist/components/core/organisms/index.d.ts +3 -0
  9. package/dist/components/core/organisms/trace-edit-focus.d.ts +14 -0
  10. package/dist/components/game/atoms/ChoiceButton.d.ts +7 -1
  11. package/dist/components/game/molecules/HealthPanel.d.ts +3 -0
  12. package/dist/components/game/molecules/IsometricCanvas.d.ts +4 -1
  13. package/dist/components/game/molecules/PowerupSlots.d.ts +3 -0
  14. package/dist/components/game/molecules/TurnPanel.d.ts +3 -0
  15. package/dist/components/game/molecules/index.d.ts +1 -0
  16. package/dist/components/game/molecules/three/index.cjs +6 -6
  17. package/dist/components/game/molecules/three/index.js +6 -6
  18. package/dist/components/game/organisms/HexStrategyBoard.d.ts +37 -0
  19. package/dist/components/game/organisms/index.d.ts +2 -0
  20. package/dist/components/game/organisms/utils/isometric.d.ts +20 -7
  21. package/dist/components/index.cjs +1241 -53
  22. package/dist/components/index.js +1243 -60
  23. package/dist/hooks/index.cjs +94 -0
  24. package/dist/hooks/index.d.ts +1 -0
  25. package/dist/hooks/index.js +95 -2
  26. package/dist/hooks/useAgentTrace.d.ts +85 -0
  27. package/dist/providers/index.cjs +210 -45
  28. package/dist/providers/index.js +213 -48
  29. package/dist/runtime/index.cjs +212 -47
  30. package/dist/runtime/index.js +215 -50
  31. package/package.json +2 -2
@@ -8021,6 +8021,8 @@ var init_DialogueBubble = __esm({
8021
8021
  function ChoiceButton({
8022
8022
  text = "Charge forward into the fray",
8023
8023
  index,
8024
+ assetUrl,
8025
+ icon,
8024
8026
  disabled = false,
8025
8027
  selected = false,
8026
8028
  onClick,
@@ -8053,6 +8055,23 @@ function ChoiceButton({
8053
8055
  ]
8054
8056
  }
8055
8057
  ),
8058
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
8059
+ "img",
8060
+ {
8061
+ src: assetUrl,
8062
+ alt: "",
8063
+ width: 16,
8064
+ height: 16,
8065
+ style: { imageRendering: "pixelated", objectFit: "contain" },
8066
+ className: "flex-shrink-0"
8067
+ }
8068
+ ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
8069
+ const I = resolveIcon(icon);
8070
+ return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" }) : null;
8071
+ })() : /* @__PURE__ */ (() => {
8072
+ const I = icon;
8073
+ return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" });
8074
+ })() }) : null,
8056
8075
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm leading-snug", children: text })
8057
8076
  ]
8058
8077
  }
@@ -8061,6 +8080,7 @@ function ChoiceButton({
8061
8080
  var init_ChoiceButton = __esm({
8062
8081
  "components/game/atoms/ChoiceButton.tsx"() {
8063
8082
  init_cn();
8083
+ init_Icon();
8064
8084
  ChoiceButton.displayName = "ChoiceButton";
8065
8085
  }
8066
8086
  });
@@ -11286,16 +11306,26 @@ var init_useUnitSpriteAtlas = __esm({
11286
11306
  });
11287
11307
 
11288
11308
  // components/game/organisms/utils/isometric.ts
11289
- function isoToScreen(tileX, tileY, scale, baseOffsetX) {
11309
+ function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
11290
11310
  const scaledTileWidth = TILE_WIDTH * scale;
11291
11311
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
11312
+ if (layout === "hex") {
11313
+ const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
11314
+ const screenY2 = tileY * (scaledFloorHeight * 0.75);
11315
+ return { x: screenX2, y: screenY2 };
11316
+ }
11292
11317
  const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
11293
11318
  const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
11294
11319
  return { x: screenX, y: screenY };
11295
11320
  }
11296
- function screenToIso(screenX, screenY, scale, baseOffsetX) {
11321
+ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
11297
11322
  const scaledTileWidth = TILE_WIDTH * scale;
11298
11323
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
11324
+ if (layout === "hex") {
11325
+ const row = Math.round(screenY / (scaledFloorHeight * 0.75));
11326
+ const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
11327
+ return { x: col, y: row };
11328
+ }
11299
11329
  const adjustedX = screenX - baseOffsetX;
11300
11330
  const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
11301
11331
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
@@ -11345,6 +11375,7 @@ function IsometricCanvas({
11345
11375
  tileHoverEvent,
11346
11376
  tileLeaveEvent,
11347
11377
  // Rendering options
11378
+ tileLayout = "isometric",
11348
11379
  scale = 0.4,
11349
11380
  debug: debug2 = false,
11350
11381
  backgroundImage = "",
@@ -11414,13 +11445,17 @@ function IsometricCanvas({
11414
11445
  );
11415
11446
  const sortedTiles = React85.useMemo(() => {
11416
11447
  const tiles = [...tilesProp];
11417
- tiles.sort((a, b) => {
11418
- const depthA = a.x + a.y;
11419
- const depthB = b.x + b.y;
11420
- return depthA !== depthB ? depthA - depthB : a.y - b.y;
11421
- });
11448
+ if (tileLayout === "hex") {
11449
+ tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
11450
+ } else {
11451
+ tiles.sort((a, b) => {
11452
+ const depthA = a.x + a.y;
11453
+ const depthB = b.x + b.y;
11454
+ return depthA !== depthB ? depthA - depthB : a.y - b.y;
11455
+ });
11456
+ }
11422
11457
  return tiles;
11423
- }, [tilesProp]);
11458
+ }, [tilesProp, tileLayout]);
11424
11459
  const gridWidth = React85.useMemo(() => {
11425
11460
  if (sortedTiles.length === 0) return 0;
11426
11461
  return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
@@ -11534,18 +11569,19 @@ function IsometricCanvas({
11534
11569
  miniCanvas.width = mW;
11535
11570
  miniCanvas.height = mH;
11536
11571
  mCtx.clearRect(0, 0, mW, mH);
11537
- const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
11572
+ const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
11538
11573
  const minX = Math.min(...allScreenPos.map((p2) => p2.x));
11539
11574
  const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
11540
11575
  const minY = Math.min(...allScreenPos.map((p2) => p2.y));
11541
- const maxY = Math.max(...allScreenPos.map((p2) => p2.y + scaledTileHeight));
11576
+ const tileBottomExtent = tileLayout === "hex" ? scaledTileWidth : scaledTileHeight;
11577
+ const maxY = Math.max(...allScreenPos.map((p2) => p2.y + tileBottomExtent));
11542
11578
  const worldW = maxX - minX;
11543
11579
  const worldH = maxY - minY;
11544
11580
  const scaleM = Math.min(mW / worldW, mH / worldH) * 0.9;
11545
11581
  const offsetMx = (mW - worldW * scaleM) / 2;
11546
11582
  const offsetMy = (mH - worldH * scaleM) / 2;
11547
11583
  for (const tile of sortedTiles) {
11548
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
11584
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
11549
11585
  const mx = (pos.x - minX) * scaleM + offsetMx;
11550
11586
  const my = (pos.y - minY) * scaleM + offsetMy;
11551
11587
  const mTileW = scaledTileWidth * scaleM;
@@ -11561,7 +11597,7 @@ function IsometricCanvas({
11561
11597
  }
11562
11598
  for (const unit of units) {
11563
11599
  if (!unit.position) continue;
11564
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11600
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11565
11601
  const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
11566
11602
  const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
11567
11603
  mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
@@ -11577,7 +11613,7 @@ function IsometricCanvas({
11577
11613
  mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
11578
11614
  mCtx.lineWidth = 1;
11579
11615
  mCtx.strokeRect(vLeft, vTop, vW, vH);
11580
- }, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
11616
+ }, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
11581
11617
  const draw = React85.useCallback((animTime) => {
11582
11618
  const canvas = canvasRef.current;
11583
11619
  if (!canvas) return;
@@ -11617,7 +11653,7 @@ function IsometricCanvas({
11617
11653
  const visTop = cam.y - viewportSize.height / cam.zoom;
11618
11654
  const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
11619
11655
  for (const tile of sortedTiles) {
11620
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
11656
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
11621
11657
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11622
11658
  continue;
11623
11659
  }
@@ -11630,7 +11666,7 @@ function IsometricCanvas({
11630
11666
  const drawW = scaledTileWidth;
11631
11667
  const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
11632
11668
  const drawX = pos.x;
11633
- const drawY = pos.y + scaledTileHeight - drawH;
11669
+ const drawY = tileLayout === "hex" ? pos.y : pos.y + scaledTileHeight - drawH;
11634
11670
  ctx.drawImage(img, drawX, drawY, drawW, drawH);
11635
11671
  }
11636
11672
  } else {
@@ -11697,12 +11733,13 @@ function IsometricCanvas({
11697
11733
  }
11698
11734
  }
11699
11735
  const sortedFeatures = [...features].sort((a, b) => {
11736
+ if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
11700
11737
  const depthA = a.x + a.y;
11701
11738
  const depthB = b.x + b.y;
11702
11739
  return depthA !== depthB ? depthA - depthB : a.y - b.y;
11703
11740
  });
11704
11741
  for (const feature of sortedFeatures) {
11705
- const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
11742
+ const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
11706
11743
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11707
11744
  continue;
11708
11745
  }
@@ -11737,12 +11774,13 @@ function IsometricCanvas({
11737
11774
  }
11738
11775
  const unitsWithPosition = units.filter((u) => !!u.position);
11739
11776
  const sortedUnits = [...unitsWithPosition].sort((a, b) => {
11777
+ if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
11740
11778
  const depthA = a.position.x + a.position.y;
11741
11779
  const depthB = b.position.x + b.position.y;
11742
11780
  return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
11743
11781
  });
11744
11782
  for (const unit of sortedUnits) {
11745
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11783
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11746
11784
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11747
11785
  continue;
11748
11786
  }
@@ -11762,7 +11800,7 @@ function IsometricCanvas({
11762
11800
  drawH = maxUnitW / ar;
11763
11801
  }
11764
11802
  if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
11765
- const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
11803
+ const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
11766
11804
  const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
11767
11805
  const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
11768
11806
  ctx.save();
@@ -11891,6 +11929,7 @@ function IsometricCanvas({
11891
11929
  units,
11892
11930
  features,
11893
11931
  selectedUnitId,
11932
+ tileLayout,
11894
11933
  scale,
11895
11934
  debug2,
11896
11935
  resolveTerrainSpriteUrl,
@@ -11919,14 +11958,14 @@ function IsometricCanvas({
11919
11958
  if (!selectedUnitId) return;
11920
11959
  const unit = units.find((u) => u.id === selectedUnitId);
11921
11960
  if (!unit?.position) return;
11922
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11961
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11923
11962
  const centerX = pos.x + scaledTileWidth / 2;
11924
11963
  const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
11925
11964
  targetCameraRef.current = {
11926
11965
  x: centerX - viewportSize.width / 2,
11927
11966
  y: centerY - viewportSize.height / 2
11928
11967
  };
11929
- }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11968
+ }, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11930
11969
  React85.useEffect(() => {
11931
11970
  const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
11932
11971
  draw(animTimeRef.current);
@@ -11959,13 +11998,13 @@ function IsometricCanvas({
11959
11998
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
11960
11999
  const adjustedX = world.x - scaledTileWidth / 2;
11961
12000
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
11962
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
12001
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
11963
12002
  const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
11964
12003
  if (tileExists) {
11965
12004
  if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
11966
12005
  onTileHover?.(isoPos.x, isoPos.y);
11967
12006
  }
11968
- }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
12007
+ }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
11969
12008
  const handleCanvasPointerUp = React85.useCallback((e) => {
11970
12009
  singlePointerActiveRef.current = false;
11971
12010
  if (enableCamera) handlePointerUp();
@@ -11974,7 +12013,7 @@ function IsometricCanvas({
11974
12013
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
11975
12014
  const adjustedX = world.x - scaledTileWidth / 2;
11976
12015
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
11977
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
12016
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
11978
12017
  const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
11979
12018
  if (clickedUnit && (onUnitClick || unitClickEvent)) {
11980
12019
  if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
@@ -11986,7 +12025,7 @@ function IsometricCanvas({
11986
12025
  onTileClick?.(isoPos.x, isoPos.y);
11987
12026
  }
11988
12027
  }
11989
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
12028
+ }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
11990
12029
  const handleCanvasPointerLeave = React85.useCallback(() => {
11991
12030
  handleMouseLeave();
11992
12031
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -28379,6 +28418,7 @@ function PowerupSlots({
28379
28418
  /* @__PURE__ */ jsxRuntime.jsx(
28380
28419
  ItemSlot,
28381
28420
  {
28421
+ assetUrl: powerup.assetUrl,
28382
28422
  icon: powerup.icon,
28383
28423
  label: powerup.label,
28384
28424
  rarity: "uncommon",
@@ -28628,13 +28668,26 @@ function HealthPanel({
28628
28668
  )
28629
28669
  }
28630
28670
  ),
28631
- effects && effects.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxRuntime.jsx(
28671
+ effects && effects.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28632
28672
  Badge,
28633
28673
  {
28634
28674
  variant: effectVariantMap[effect.variant ?? "neutral"],
28635
28675
  size: "sm",
28636
- icon: effect.icon,
28637
- children: effect.label
28676
+ icon: effect.assetUrl ? void 0 : effect.icon,
28677
+ children: [
28678
+ effect.assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
28679
+ "img",
28680
+ {
28681
+ src: effect.assetUrl,
28682
+ alt: "",
28683
+ width: 12,
28684
+ height: 12,
28685
+ style: { imageRendering: "pixelated", objectFit: "contain" },
28686
+ className: "flex-shrink-0 inline-block"
28687
+ }
28688
+ ),
28689
+ effect.label
28690
+ ]
28638
28691
  },
28639
28692
  i
28640
28693
  )) })
@@ -28817,15 +28870,28 @@ function TurnPanel({
28817
28870
  activeTeam
28818
28871
  }
28819
28872
  ),
28820
- actions && actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsxRuntime.jsx(
28873
+ actions && actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28821
28874
  Button,
28822
28875
  {
28823
28876
  variant: "ghost",
28824
28877
  size: "sm",
28825
28878
  disabled: action.disabled,
28826
- leftIcon: action.icon,
28879
+ leftIcon: action.assetUrl ? void 0 : action.icon,
28827
28880
  onClick: () => handleAction(action.event),
28828
- children: action.label
28881
+ children: [
28882
+ action.assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
28883
+ "img",
28884
+ {
28885
+ src: action.assetUrl,
28886
+ alt: "",
28887
+ width: 14,
28888
+ height: 14,
28889
+ style: { imageRendering: "pixelated", objectFit: "contain" },
28890
+ className: "flex-shrink-0"
28891
+ }
28892
+ ),
28893
+ action.label
28894
+ ]
28829
28895
  },
28830
28896
  i
28831
28897
  )) })
@@ -43741,9 +43807,9 @@ var init_GameCanvas3D2 = __esm({
43741
43807
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43742
43808
  const hasAtlas = unitAtlasUrl(unit) !== null;
43743
43809
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
43744
- const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
43745
- const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
43746
- const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
43810
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * gridConfig.cellSize;
43811
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * gridConfig.cellSize;
43812
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * gridConfig.cellSize;
43747
43813
  return /* @__PURE__ */ jsxRuntime.jsxs(
43748
43814
  "group",
43749
43815
  {
@@ -43790,7 +43856,7 @@ var init_GameCanvas3D2 = __esm({
43790
43856
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43791
43857
  ] })
43792
43858
  ] }),
43793
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
43859
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, billboardHeight, 0], children: [
43794
43860
  /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
43795
43861
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
43796
43862
  /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
@@ -43819,7 +43885,7 @@ var init_GameCanvas3D2 = __esm({
43819
43885
  }
43820
43886
  );
43821
43887
  },
43822
- [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
43888
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale, gridConfig]
43823
43889
  );
43824
43890
  const DefaultFeatureRenderer = React85.useCallback(
43825
43891
  ({
@@ -43907,7 +43973,7 @@ var init_GameCanvas3D2 = __esm({
43907
43973
  {
43908
43974
  ref: containerRef,
43909
43975
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
43910
- style: { height: "85vh" },
43976
+ style: { flex: "1 1 0", minHeight: "400px" },
43911
43977
  "data-orientation": orientation,
43912
43978
  "data-camera-mode": cameraMode,
43913
43979
  "data-overlay": overlay,
@@ -44207,13 +44273,39 @@ var init_GameBoard3D = __esm({
44207
44273
  GameBoard3D.displayName = "GameBoard3D";
44208
44274
  }
44209
44275
  });
44210
- var GameShell;
44276
+ function getSlotContentRenderer2() {
44277
+ if (_scr) return _scr;
44278
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
44279
+ _scr = mod.SlotContentRenderer;
44280
+ return _scr;
44281
+ }
44282
+ function resolveDescriptor(value, idPrefix) {
44283
+ if (value === null || value === void 0) return value;
44284
+ if (React85__namespace.default.isValidElement(value)) return value;
44285
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
44286
+ if (Array.isArray(value)) {
44287
+ return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React85__namespace.default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
44288
+ }
44289
+ if (typeof value === "object") {
44290
+ const rec = value;
44291
+ if (typeof rec.type === "string" && patterns.getComponentForPattern(rec.type) !== null) {
44292
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
44293
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
44294
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
44295
+ const SCR = getSlotContentRenderer2();
44296
+ return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
44297
+ }
44298
+ }
44299
+ return null;
44300
+ }
44301
+ var _scr, GameShell;
44211
44302
  var init_GameShell = __esm({
44212
44303
  "components/game/templates/GameShell.tsx"() {
44213
44304
  init_cn();
44214
44305
  init_Box();
44215
44306
  init_Stack();
44216
44307
  init_Typography();
44308
+ _scr = null;
44217
44309
  GameShell = ({
44218
44310
  appName = "Game",
44219
44311
  hud,
@@ -44262,7 +44354,7 @@ var init_GameShell = __esm({
44262
44354
  children: appName
44263
44355
  }
44264
44356
  ),
44265
- hud && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "game-shell__hud", children: hud })
44357
+ hud && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "game-shell__hud", children: resolveDescriptor(hud, "gs-hud") })
44266
44358
  ]
44267
44359
  }
44268
44360
  ),
@@ -44275,7 +44367,7 @@ var init_GameShell = __esm({
44275
44367
  overflow: "hidden",
44276
44368
  position: "relative"
44277
44369
  },
44278
- children
44370
+ children: resolveDescriptor(children, "gs-children")
44279
44371
  }
44280
44372
  )
44281
44373
  ]
@@ -44285,7 +44377,32 @@ var init_GameShell = __esm({
44285
44377
  GameShell.displayName = "GameShell";
44286
44378
  }
44287
44379
  });
44288
- var GameTemplate;
44380
+ function getSlotContentRenderer3() {
44381
+ if (_scr2) return _scr2;
44382
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
44383
+ _scr2 = mod.SlotContentRenderer;
44384
+ return _scr2;
44385
+ }
44386
+ function resolveDescriptor2(value, idPrefix) {
44387
+ if (value === null || value === void 0) return value;
44388
+ if (React85__namespace.default.isValidElement(value)) return value;
44389
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
44390
+ if (Array.isArray(value)) {
44391
+ return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React85__namespace.default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
44392
+ }
44393
+ if (typeof value === "object") {
44394
+ const rec = value;
44395
+ if (typeof rec.type === "string" && patterns.getComponentForPattern(rec.type) !== null) {
44396
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
44397
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
44398
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
44399
+ const SCR = getSlotContentRenderer3();
44400
+ return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
44401
+ }
44402
+ }
44403
+ return null;
44404
+ }
44405
+ var _scr2, GameTemplate;
44289
44406
  var init_GameTemplate = __esm({
44290
44407
  "components/game/templates/GameTemplate.tsx"() {
44291
44408
  init_cn();
@@ -44293,6 +44410,7 @@ var init_GameTemplate = __esm({
44293
44410
  init_Stack();
44294
44411
  init_Typography();
44295
44412
  init_Button();
44413
+ _scr2 = null;
44296
44414
  GameTemplate = ({
44297
44415
  entity,
44298
44416
  title = "Game",
@@ -44360,13 +44478,13 @@ var init_GameTemplate = __esm({
44360
44478
  fullWidth: true,
44361
44479
  className: "flex-1 bg-muted",
44362
44480
  children: [
44363
- children,
44481
+ resolveDescriptor2(children, "gt-children"),
44364
44482
  hud && /* @__PURE__ */ jsxRuntime.jsx(
44365
44483
  Box,
44366
44484
  {
44367
44485
  position: "absolute",
44368
44486
  className: "top-0 left-0 right-0 pointer-events-none",
44369
- children: /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
44487
+ children: /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: resolveDescriptor2(hud, "gt-hud") })
44370
44488
  }
44371
44489
  )
44372
44490
  ]
@@ -44391,7 +44509,7 @@ var init_GameTemplate = __esm({
44391
44509
  children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h6", children: "Debug Panel" })
44392
44510
  }
44393
44511
  ),
44394
- /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", children: debugPanel })
44512
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", children: resolveDescriptor2(debugPanel, "gt-debug") })
44395
44513
  ]
44396
44514
  }
44397
44515
  )
@@ -44561,6 +44679,48 @@ var init_HeroOrganism = __esm({
44561
44679
  _HeroClickInterceptor.displayName = "_HeroClickInterceptor";
44562
44680
  }
44563
44681
  });
44682
+ function HexStrategyBoard({
44683
+ tiles,
44684
+ units,
44685
+ features,
44686
+ assetManifest,
44687
+ assetBaseUrl,
44688
+ scale = 0.45,
44689
+ showMinimap = true,
44690
+ enableCamera = true,
44691
+ tileClickEvent,
44692
+ unitClickEvent,
44693
+ isLoading,
44694
+ error,
44695
+ className
44696
+ }) {
44697
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
44698
+ IsometricCanvas_default,
44699
+ {
44700
+ tileLayout: "hex",
44701
+ tiles,
44702
+ units,
44703
+ features,
44704
+ assetManifest,
44705
+ assetBaseUrl,
44706
+ scale,
44707
+ showMinimap,
44708
+ enableCamera,
44709
+ tileClickEvent,
44710
+ unitClickEvent,
44711
+ isLoading,
44712
+ error
44713
+ }
44714
+ ) });
44715
+ }
44716
+ var init_HexStrategyBoard = __esm({
44717
+ "components/game/organisms/HexStrategyBoard.tsx"() {
44718
+ "use client";
44719
+ init_cn();
44720
+ init_IsometricCanvas();
44721
+ HexStrategyBoard.displayName = "HexStrategyBoard";
44722
+ }
44723
+ });
44564
44724
  var LandingPageTemplate;
44565
44725
  var init_LandingPageTemplate = __esm({
44566
44726
  "components/marketing/templates/LandingPageTemplate.tsx"() {
@@ -52370,6 +52530,7 @@ var init_component_registry_generated = __esm({
52370
52530
  init_HealthPanel();
52371
52531
  init_HeroOrganism();
52372
52532
  init_HeroSection();
52533
+ init_HexStrategyBoard();
52373
52534
  init_Icon();
52374
52535
  init_InfiniteScrollSentinel();
52375
52536
  init_Input();
@@ -52706,6 +52867,7 @@ var init_component_registry_generated = __esm({
52706
52867
  "HealthPanel": HealthPanel,
52707
52868
  "HeroOrganism": HeroOrganism,
52708
52869
  "HeroSection": HeroSection,
52870
+ "HexStrategyBoard": HexStrategyBoard,
52709
52871
  "Icon": Icon,
52710
52872
  "InfiniteScrollSentinel": InfiniteScrollSentinel,
52711
52873
  "Input": Input,
@@ -52907,7 +53069,7 @@ function getSlotFallback(slot, config) {
52907
53069
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
52908
53070
  return /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { variant });
52909
53071
  }
52910
- function getComponentForPattern(patternType) {
53072
+ function getComponentForPattern3(patternType) {
52911
53073
  const mapping = patterns.getComponentForPattern(patternType);
52912
53074
  if (!mapping) {
52913
53075
  return null;
@@ -53538,7 +53700,8 @@ function SlotContentRenderer({
53538
53700
  entityDef = schemaCtx.entities.get(linkedEntity);
53539
53701
  }
53540
53702
  }
53541
- const PatternComponent = getComponentForPattern(content.pattern);
53703
+ const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
53704
+ const PatternComponent = getComponentForPattern3(content.pattern);
53542
53705
  if (PatternComponent) {
53543
53706
  const childrenConfig = content.props.children;
53544
53707
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -53636,6 +53799,7 @@ function SlotContentRenderer({
53636
53799
  "data-orb-entity": content.entity,
53637
53800
  "data-orb-path": myPath,
53638
53801
  "data-orb-pattern": content.pattern,
53802
+ "data-orb-orbital": orbitalName,
53639
53803
  children: renderedChildren !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(PatternComponent, { ...finalProps, children: renderedChildren }) : /* @__PURE__ */ jsxRuntime.jsx(PatternComponent, { ...finalProps })
53640
53804
  }
53641
53805
  );
@@ -53655,6 +53819,7 @@ function SlotContentRenderer({
53655
53819
  "data-orb-entity": content.entity,
53656
53820
  "data-orb-path": patternPath ?? "root",
53657
53821
  "data-orb-pattern": content.pattern,
53822
+ "data-orb-orbital": orbitalName,
53658
53823
  children: content.props.children ?? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "p-4 text-sm text-muted-foreground border border-dashed border-border rounded", children: [
53659
53824
  "Unknown pattern: ",
53660
53825
  content.pattern,