@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
@@ -48,7 +48,7 @@ import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoade
48
48
  import { clone } from 'three/examples/jsm/utils/SkeletonUtils';
49
49
  import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
50
50
  import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
51
- import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
51
+ import { getPatternDefinition, getComponentForPattern } from '@almadar/patterns';
52
52
 
53
53
  var __defProp = Object.defineProperty;
54
54
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -7974,6 +7974,8 @@ var init_DialogueBubble = __esm({
7974
7974
  function ChoiceButton({
7975
7975
  text = "Charge forward into the fray",
7976
7976
  index,
7977
+ assetUrl,
7978
+ icon,
7977
7979
  disabled = false,
7978
7980
  selected = false,
7979
7981
  onClick,
@@ -8006,6 +8008,23 @@ function ChoiceButton({
8006
8008
  ]
8007
8009
  }
8008
8010
  ),
8011
+ assetUrl ? /* @__PURE__ */ jsx(
8012
+ "img",
8013
+ {
8014
+ src: assetUrl,
8015
+ alt: "",
8016
+ width: 16,
8017
+ height: 16,
8018
+ style: { imageRendering: "pixelated", objectFit: "contain" },
8019
+ className: "flex-shrink-0"
8020
+ }
8021
+ ) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
8022
+ const I = resolveIcon(icon);
8023
+ return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
8024
+ })() : /* @__PURE__ */ (() => {
8025
+ const I = icon;
8026
+ return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
8027
+ })() }) : null,
8009
8028
  /* @__PURE__ */ jsx("span", { className: "text-sm leading-snug", children: text })
8010
8029
  ]
8011
8030
  }
@@ -8014,6 +8033,7 @@ function ChoiceButton({
8014
8033
  var init_ChoiceButton = __esm({
8015
8034
  "components/game/atoms/ChoiceButton.tsx"() {
8016
8035
  init_cn();
8036
+ init_Icon();
8017
8037
  ChoiceButton.displayName = "ChoiceButton";
8018
8038
  }
8019
8039
  });
@@ -11239,16 +11259,26 @@ var init_useUnitSpriteAtlas = __esm({
11239
11259
  });
11240
11260
 
11241
11261
  // components/game/organisms/utils/isometric.ts
11242
- function isoToScreen(tileX, tileY, scale, baseOffsetX) {
11262
+ function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
11243
11263
  const scaledTileWidth = TILE_WIDTH * scale;
11244
11264
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
11265
+ if (layout === "hex") {
11266
+ const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
11267
+ const screenY2 = tileY * (scaledFloorHeight * 0.75);
11268
+ return { x: screenX2, y: screenY2 };
11269
+ }
11245
11270
  const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
11246
11271
  const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
11247
11272
  return { x: screenX, y: screenY };
11248
11273
  }
11249
- function screenToIso(screenX, screenY, scale, baseOffsetX) {
11274
+ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
11250
11275
  const scaledTileWidth = TILE_WIDTH * scale;
11251
11276
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
11277
+ if (layout === "hex") {
11278
+ const row = Math.round(screenY / (scaledFloorHeight * 0.75));
11279
+ const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
11280
+ return { x: col, y: row };
11281
+ }
11252
11282
  const adjustedX = screenX - baseOffsetX;
11253
11283
  const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
11254
11284
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
@@ -11298,6 +11328,7 @@ function IsometricCanvas({
11298
11328
  tileHoverEvent,
11299
11329
  tileLeaveEvent,
11300
11330
  // Rendering options
11331
+ tileLayout = "isometric",
11301
11332
  scale = 0.4,
11302
11333
  debug: debug2 = false,
11303
11334
  backgroundImage = "",
@@ -11367,13 +11398,17 @@ function IsometricCanvas({
11367
11398
  );
11368
11399
  const sortedTiles = useMemo(() => {
11369
11400
  const tiles = [...tilesProp];
11370
- tiles.sort((a, b) => {
11371
- const depthA = a.x + a.y;
11372
- const depthB = b.x + b.y;
11373
- return depthA !== depthB ? depthA - depthB : a.y - b.y;
11374
- });
11401
+ if (tileLayout === "hex") {
11402
+ tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
11403
+ } else {
11404
+ tiles.sort((a, b) => {
11405
+ const depthA = a.x + a.y;
11406
+ const depthB = b.x + b.y;
11407
+ return depthA !== depthB ? depthA - depthB : a.y - b.y;
11408
+ });
11409
+ }
11375
11410
  return tiles;
11376
- }, [tilesProp]);
11411
+ }, [tilesProp, tileLayout]);
11377
11412
  const gridWidth = useMemo(() => {
11378
11413
  if (sortedTiles.length === 0) return 0;
11379
11414
  return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
@@ -11487,18 +11522,19 @@ function IsometricCanvas({
11487
11522
  miniCanvas.width = mW;
11488
11523
  miniCanvas.height = mH;
11489
11524
  mCtx.clearRect(0, 0, mW, mH);
11490
- const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
11525
+ const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
11491
11526
  const minX = Math.min(...allScreenPos.map((p2) => p2.x));
11492
11527
  const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
11493
11528
  const minY = Math.min(...allScreenPos.map((p2) => p2.y));
11494
- const maxY = Math.max(...allScreenPos.map((p2) => p2.y + scaledTileHeight));
11529
+ const tileBottomExtent = tileLayout === "hex" ? scaledTileWidth : scaledTileHeight;
11530
+ const maxY = Math.max(...allScreenPos.map((p2) => p2.y + tileBottomExtent));
11495
11531
  const worldW = maxX - minX;
11496
11532
  const worldH = maxY - minY;
11497
11533
  const scaleM = Math.min(mW / worldW, mH / worldH) * 0.9;
11498
11534
  const offsetMx = (mW - worldW * scaleM) / 2;
11499
11535
  const offsetMy = (mH - worldH * scaleM) / 2;
11500
11536
  for (const tile of sortedTiles) {
11501
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
11537
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
11502
11538
  const mx = (pos.x - minX) * scaleM + offsetMx;
11503
11539
  const my = (pos.y - minY) * scaleM + offsetMy;
11504
11540
  const mTileW = scaledTileWidth * scaleM;
@@ -11514,7 +11550,7 @@ function IsometricCanvas({
11514
11550
  }
11515
11551
  for (const unit of units) {
11516
11552
  if (!unit.position) continue;
11517
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11553
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11518
11554
  const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
11519
11555
  const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
11520
11556
  mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
@@ -11530,7 +11566,7 @@ function IsometricCanvas({
11530
11566
  mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
11531
11567
  mCtx.lineWidth = 1;
11532
11568
  mCtx.strokeRect(vLeft, vTop, vW, vH);
11533
- }, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
11569
+ }, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
11534
11570
  const draw = useCallback((animTime) => {
11535
11571
  const canvas = canvasRef.current;
11536
11572
  if (!canvas) return;
@@ -11570,7 +11606,7 @@ function IsometricCanvas({
11570
11606
  const visTop = cam.y - viewportSize.height / cam.zoom;
11571
11607
  const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
11572
11608
  for (const tile of sortedTiles) {
11573
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
11609
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
11574
11610
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11575
11611
  continue;
11576
11612
  }
@@ -11583,7 +11619,7 @@ function IsometricCanvas({
11583
11619
  const drawW = scaledTileWidth;
11584
11620
  const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
11585
11621
  const drawX = pos.x;
11586
- const drawY = pos.y + scaledTileHeight - drawH;
11622
+ const drawY = tileLayout === "hex" ? pos.y : pos.y + scaledTileHeight - drawH;
11587
11623
  ctx.drawImage(img, drawX, drawY, drawW, drawH);
11588
11624
  }
11589
11625
  } else {
@@ -11650,12 +11686,13 @@ function IsometricCanvas({
11650
11686
  }
11651
11687
  }
11652
11688
  const sortedFeatures = [...features].sort((a, b) => {
11689
+ if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
11653
11690
  const depthA = a.x + a.y;
11654
11691
  const depthB = b.x + b.y;
11655
11692
  return depthA !== depthB ? depthA - depthB : a.y - b.y;
11656
11693
  });
11657
11694
  for (const feature of sortedFeatures) {
11658
- const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
11695
+ const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
11659
11696
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11660
11697
  continue;
11661
11698
  }
@@ -11690,12 +11727,13 @@ function IsometricCanvas({
11690
11727
  }
11691
11728
  const unitsWithPosition = units.filter((u) => !!u.position);
11692
11729
  const sortedUnits = [...unitsWithPosition].sort((a, b) => {
11730
+ if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
11693
11731
  const depthA = a.position.x + a.position.y;
11694
11732
  const depthB = b.position.x + b.position.y;
11695
11733
  return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
11696
11734
  });
11697
11735
  for (const unit of sortedUnits) {
11698
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11736
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11699
11737
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11700
11738
  continue;
11701
11739
  }
@@ -11715,7 +11753,7 @@ function IsometricCanvas({
11715
11753
  drawH = maxUnitW / ar;
11716
11754
  }
11717
11755
  if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
11718
- const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
11756
+ const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
11719
11757
  const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
11720
11758
  const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
11721
11759
  ctx.save();
@@ -11844,6 +11882,7 @@ function IsometricCanvas({
11844
11882
  units,
11845
11883
  features,
11846
11884
  selectedUnitId,
11885
+ tileLayout,
11847
11886
  scale,
11848
11887
  debug2,
11849
11888
  resolveTerrainSpriteUrl,
@@ -11872,14 +11911,14 @@ function IsometricCanvas({
11872
11911
  if (!selectedUnitId) return;
11873
11912
  const unit = units.find((u) => u.id === selectedUnitId);
11874
11913
  if (!unit?.position) return;
11875
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11914
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11876
11915
  const centerX = pos.x + scaledTileWidth / 2;
11877
11916
  const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
11878
11917
  targetCameraRef.current = {
11879
11918
  x: centerX - viewportSize.width / 2,
11880
11919
  y: centerY - viewportSize.height / 2
11881
11920
  };
11882
- }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11921
+ }, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11883
11922
  useEffect(() => {
11884
11923
  const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
11885
11924
  draw(animTimeRef.current);
@@ -11912,13 +11951,13 @@ function IsometricCanvas({
11912
11951
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
11913
11952
  const adjustedX = world.x - scaledTileWidth / 2;
11914
11953
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
11915
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
11954
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
11916
11955
  const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
11917
11956
  if (tileExists) {
11918
11957
  if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
11919
11958
  onTileHover?.(isoPos.x, isoPos.y);
11920
11959
  }
11921
- }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
11960
+ }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
11922
11961
  const handleCanvasPointerUp = useCallback((e) => {
11923
11962
  singlePointerActiveRef.current = false;
11924
11963
  if (enableCamera) handlePointerUp();
@@ -11927,7 +11966,7 @@ function IsometricCanvas({
11927
11966
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
11928
11967
  const adjustedX = world.x - scaledTileWidth / 2;
11929
11968
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
11930
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
11969
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
11931
11970
  const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
11932
11971
  if (clickedUnit && (onUnitClick || unitClickEvent)) {
11933
11972
  if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
@@ -11939,7 +11978,7 @@ function IsometricCanvas({
11939
11978
  onTileClick?.(isoPos.x, isoPos.y);
11940
11979
  }
11941
11980
  }
11942
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
11981
+ }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
11943
11982
  const handleCanvasPointerLeave = useCallback(() => {
11944
11983
  handleMouseLeave();
11945
11984
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -28332,6 +28371,7 @@ function PowerupSlots({
28332
28371
  /* @__PURE__ */ jsx(
28333
28372
  ItemSlot,
28334
28373
  {
28374
+ assetUrl: powerup.assetUrl,
28335
28375
  icon: powerup.icon,
28336
28376
  label: powerup.label,
28337
28377
  rarity: "uncommon",
@@ -28581,13 +28621,26 @@ function HealthPanel({
28581
28621
  )
28582
28622
  }
28583
28623
  ),
28584
- effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsx(
28624
+ effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxs(
28585
28625
  Badge,
28586
28626
  {
28587
28627
  variant: effectVariantMap[effect.variant ?? "neutral"],
28588
28628
  size: "sm",
28589
- icon: effect.icon,
28590
- children: effect.label
28629
+ icon: effect.assetUrl ? void 0 : effect.icon,
28630
+ children: [
28631
+ effect.assetUrl && /* @__PURE__ */ jsx(
28632
+ "img",
28633
+ {
28634
+ src: effect.assetUrl,
28635
+ alt: "",
28636
+ width: 12,
28637
+ height: 12,
28638
+ style: { imageRendering: "pixelated", objectFit: "contain" },
28639
+ className: "flex-shrink-0 inline-block"
28640
+ }
28641
+ ),
28642
+ effect.label
28643
+ ]
28591
28644
  },
28592
28645
  i
28593
28646
  )) })
@@ -28770,15 +28823,28 @@ function TurnPanel({
28770
28823
  activeTeam
28771
28824
  }
28772
28825
  ),
28773
- actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsx(
28826
+ actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsxs(
28774
28827
  Button,
28775
28828
  {
28776
28829
  variant: "ghost",
28777
28830
  size: "sm",
28778
28831
  disabled: action.disabled,
28779
- leftIcon: action.icon,
28832
+ leftIcon: action.assetUrl ? void 0 : action.icon,
28780
28833
  onClick: () => handleAction(action.event),
28781
- children: action.label
28834
+ children: [
28835
+ action.assetUrl && /* @__PURE__ */ jsx(
28836
+ "img",
28837
+ {
28838
+ src: action.assetUrl,
28839
+ alt: "",
28840
+ width: 14,
28841
+ height: 14,
28842
+ style: { imageRendering: "pixelated", objectFit: "contain" },
28843
+ className: "flex-shrink-0"
28844
+ }
28845
+ ),
28846
+ action.label
28847
+ ]
28782
28848
  },
28783
28849
  i
28784
28850
  )) })
@@ -43694,9 +43760,9 @@ var init_GameCanvas3D2 = __esm({
43694
43760
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43695
43761
  const hasAtlas = unitAtlasUrl(unit) !== null;
43696
43762
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
43697
- const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
43698
- const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
43699
- const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
43763
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * gridConfig.cellSize;
43764
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * gridConfig.cellSize;
43765
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * gridConfig.cellSize;
43700
43766
  return /* @__PURE__ */ jsxs(
43701
43767
  "group",
43702
43768
  {
@@ -43743,7 +43809,7 @@ var init_GameCanvas3D2 = __esm({
43743
43809
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
43744
43810
  ] })
43745
43811
  ] }),
43746
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
43812
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, billboardHeight, 0], children: [
43747
43813
  /* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
43748
43814
  /* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
43749
43815
  /* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
@@ -43772,7 +43838,7 @@ var init_GameCanvas3D2 = __esm({
43772
43838
  }
43773
43839
  );
43774
43840
  },
43775
- [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
43841
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale, gridConfig]
43776
43842
  );
43777
43843
  const DefaultFeatureRenderer = useCallback(
43778
43844
  ({
@@ -43860,7 +43926,7 @@ var init_GameCanvas3D2 = __esm({
43860
43926
  {
43861
43927
  ref: containerRef,
43862
43928
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
43863
- style: { height: "85vh" },
43929
+ style: { flex: "1 1 0", minHeight: "400px" },
43864
43930
  "data-orientation": orientation,
43865
43931
  "data-camera-mode": cameraMode,
43866
43932
  "data-overlay": overlay,
@@ -44160,13 +44226,39 @@ var init_GameBoard3D = __esm({
44160
44226
  GameBoard3D.displayName = "GameBoard3D";
44161
44227
  }
44162
44228
  });
44163
- var GameShell;
44229
+ function getSlotContentRenderer2() {
44230
+ if (_scr) return _scr;
44231
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
44232
+ _scr = mod.SlotContentRenderer;
44233
+ return _scr;
44234
+ }
44235
+ function resolveDescriptor(value, idPrefix) {
44236
+ if (value === null || value === void 0) return value;
44237
+ if (React85__default.isValidElement(value)) return value;
44238
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
44239
+ if (Array.isArray(value)) {
44240
+ return value.map((item, i) => /* @__PURE__ */ jsx(React85__default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
44241
+ }
44242
+ if (typeof value === "object") {
44243
+ const rec = value;
44244
+ if (typeof rec.type === "string" && getComponentForPattern(rec.type) !== null) {
44245
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
44246
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
44247
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
44248
+ const SCR = getSlotContentRenderer2();
44249
+ return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
44250
+ }
44251
+ }
44252
+ return null;
44253
+ }
44254
+ var _scr, GameShell;
44164
44255
  var init_GameShell = __esm({
44165
44256
  "components/game/templates/GameShell.tsx"() {
44166
44257
  init_cn();
44167
44258
  init_Box();
44168
44259
  init_Stack();
44169
44260
  init_Typography();
44261
+ _scr = null;
44170
44262
  GameShell = ({
44171
44263
  appName = "Game",
44172
44264
  hud,
@@ -44215,7 +44307,7 @@ var init_GameShell = __esm({
44215
44307
  children: appName
44216
44308
  }
44217
44309
  ),
44218
- hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", children: hud })
44310
+ hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", children: resolveDescriptor(hud, "gs-hud") })
44219
44311
  ]
44220
44312
  }
44221
44313
  ),
@@ -44228,7 +44320,7 @@ var init_GameShell = __esm({
44228
44320
  overflow: "hidden",
44229
44321
  position: "relative"
44230
44322
  },
44231
- children
44323
+ children: resolveDescriptor(children, "gs-children")
44232
44324
  }
44233
44325
  )
44234
44326
  ]
@@ -44238,7 +44330,32 @@ var init_GameShell = __esm({
44238
44330
  GameShell.displayName = "GameShell";
44239
44331
  }
44240
44332
  });
44241
- var GameTemplate;
44333
+ function getSlotContentRenderer3() {
44334
+ if (_scr2) return _scr2;
44335
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
44336
+ _scr2 = mod.SlotContentRenderer;
44337
+ return _scr2;
44338
+ }
44339
+ function resolveDescriptor2(value, idPrefix) {
44340
+ if (value === null || value === void 0) return value;
44341
+ if (React85__default.isValidElement(value)) return value;
44342
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
44343
+ if (Array.isArray(value)) {
44344
+ return value.map((item, i) => /* @__PURE__ */ jsx(React85__default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
44345
+ }
44346
+ if (typeof value === "object") {
44347
+ const rec = value;
44348
+ if (typeof rec.type === "string" && getComponentForPattern(rec.type) !== null) {
44349
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
44350
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
44351
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
44352
+ const SCR = getSlotContentRenderer3();
44353
+ return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
44354
+ }
44355
+ }
44356
+ return null;
44357
+ }
44358
+ var _scr2, GameTemplate;
44242
44359
  var init_GameTemplate = __esm({
44243
44360
  "components/game/templates/GameTemplate.tsx"() {
44244
44361
  init_cn();
@@ -44246,6 +44363,7 @@ var init_GameTemplate = __esm({
44246
44363
  init_Stack();
44247
44364
  init_Typography();
44248
44365
  init_Button();
44366
+ _scr2 = null;
44249
44367
  GameTemplate = ({
44250
44368
  entity,
44251
44369
  title = "Game",
@@ -44313,13 +44431,13 @@ var init_GameTemplate = __esm({
44313
44431
  fullWidth: true,
44314
44432
  className: "flex-1 bg-muted",
44315
44433
  children: [
44316
- children,
44434
+ resolveDescriptor2(children, "gt-children"),
44317
44435
  hud && /* @__PURE__ */ jsx(
44318
44436
  Box,
44319
44437
  {
44320
44438
  position: "absolute",
44321
44439
  className: "top-0 left-0 right-0 pointer-events-none",
44322
- children: /* @__PURE__ */ jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
44440
+ children: /* @__PURE__ */ jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: resolveDescriptor2(hud, "gt-hud") })
44323
44441
  }
44324
44442
  )
44325
44443
  ]
@@ -44344,7 +44462,7 @@ var init_GameTemplate = __esm({
44344
44462
  children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Debug Panel" })
44345
44463
  }
44346
44464
  ),
44347
- /* @__PURE__ */ jsx(Box, { padding: "md", children: debugPanel })
44465
+ /* @__PURE__ */ jsx(Box, { padding: "md", children: resolveDescriptor2(debugPanel, "gt-debug") })
44348
44466
  ]
44349
44467
  }
44350
44468
  )
@@ -44514,6 +44632,48 @@ var init_HeroOrganism = __esm({
44514
44632
  _HeroClickInterceptor.displayName = "_HeroClickInterceptor";
44515
44633
  }
44516
44634
  });
44635
+ function HexStrategyBoard({
44636
+ tiles,
44637
+ units,
44638
+ features,
44639
+ assetManifest,
44640
+ assetBaseUrl,
44641
+ scale = 0.45,
44642
+ showMinimap = true,
44643
+ enableCamera = true,
44644
+ tileClickEvent,
44645
+ unitClickEvent,
44646
+ isLoading,
44647
+ error,
44648
+ className
44649
+ }) {
44650
+ return /* @__PURE__ */ jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsx(
44651
+ IsometricCanvas_default,
44652
+ {
44653
+ tileLayout: "hex",
44654
+ tiles,
44655
+ units,
44656
+ features,
44657
+ assetManifest,
44658
+ assetBaseUrl,
44659
+ scale,
44660
+ showMinimap,
44661
+ enableCamera,
44662
+ tileClickEvent,
44663
+ unitClickEvent,
44664
+ isLoading,
44665
+ error
44666
+ }
44667
+ ) });
44668
+ }
44669
+ var init_HexStrategyBoard = __esm({
44670
+ "components/game/organisms/HexStrategyBoard.tsx"() {
44671
+ "use client";
44672
+ init_cn();
44673
+ init_IsometricCanvas();
44674
+ HexStrategyBoard.displayName = "HexStrategyBoard";
44675
+ }
44676
+ });
44517
44677
  var LandingPageTemplate;
44518
44678
  var init_LandingPageTemplate = __esm({
44519
44679
  "components/marketing/templates/LandingPageTemplate.tsx"() {
@@ -52323,6 +52483,7 @@ var init_component_registry_generated = __esm({
52323
52483
  init_HealthPanel();
52324
52484
  init_HeroOrganism();
52325
52485
  init_HeroSection();
52486
+ init_HexStrategyBoard();
52326
52487
  init_Icon();
52327
52488
  init_InfiniteScrollSentinel();
52328
52489
  init_Input();
@@ -52659,6 +52820,7 @@ var init_component_registry_generated = __esm({
52659
52820
  "HealthPanel": HealthPanel,
52660
52821
  "HeroOrganism": HeroOrganism,
52661
52822
  "HeroSection": HeroSection,
52823
+ "HexStrategyBoard": HexStrategyBoard,
52662
52824
  "Icon": Icon,
52663
52825
  "InfiniteScrollSentinel": InfiniteScrollSentinel,
52664
52826
  "Input": Input,
@@ -52860,8 +53022,8 @@ function getSlotFallback(slot, config) {
52860
53022
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
52861
53023
  return /* @__PURE__ */ jsx(Skeleton, { variant });
52862
53024
  }
52863
- function getComponentForPattern(patternType) {
52864
- const mapping = getComponentForPattern$1(patternType);
53025
+ function getComponentForPattern3(patternType) {
53026
+ const mapping = getComponentForPattern(patternType);
52865
53027
  if (!mapping) {
52866
53028
  return null;
52867
53029
  }
@@ -53383,7 +53545,7 @@ function isPatternConfig(value) {
53383
53545
  if (value instanceof Date) return false;
53384
53546
  if (typeof value === "function") return false;
53385
53547
  const record = value;
53386
- return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
53548
+ return "type" in record && typeof record.type === "string" && getComponentForPattern(record.type) !== null;
53387
53549
  }
53388
53550
  function isPlainConfigObject(value) {
53389
53551
  if (React85__default.isValidElement(value)) return false;
@@ -53491,7 +53653,8 @@ function SlotContentRenderer({
53491
53653
  entityDef = schemaCtx.entities.get(linkedEntity);
53492
53654
  }
53493
53655
  }
53494
- const PatternComponent = getComponentForPattern(content.pattern);
53656
+ const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
53657
+ const PatternComponent = getComponentForPattern3(content.pattern);
53495
53658
  if (PatternComponent) {
53496
53659
  const childrenConfig = content.props.children;
53497
53660
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -53589,6 +53752,7 @@ function SlotContentRenderer({
53589
53752
  "data-orb-entity": content.entity,
53590
53753
  "data-orb-path": myPath,
53591
53754
  "data-orb-pattern": content.pattern,
53755
+ "data-orb-orbital": orbitalName,
53592
53756
  children: renderedChildren !== void 0 ? /* @__PURE__ */ jsx(PatternComponent, { ...finalProps, children: renderedChildren }) : /* @__PURE__ */ jsx(PatternComponent, { ...finalProps })
53593
53757
  }
53594
53758
  );
@@ -53608,6 +53772,7 @@ function SlotContentRenderer({
53608
53772
  "data-orb-entity": content.entity,
53609
53773
  "data-orb-path": patternPath ?? "root",
53610
53774
  "data-orb-pattern": content.pattern,
53775
+ "data-orb-orbital": orbitalName,
53611
53776
  children: content.props.children ?? /* @__PURE__ */ jsxs(Box, { className: "p-4 text-sm text-muted-foreground border border-dashed border-border rounded", children: [
53612
53777
  "Unknown pattern: ",
53613
53778
  content.pattern,