@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
@@ -8063,6 +8063,8 @@ var init_DialogueBubble = __esm({
8063
8063
  function ChoiceButton({
8064
8064
  text = "Charge forward into the fray",
8065
8065
  index,
8066
+ assetUrl,
8067
+ icon,
8066
8068
  disabled = false,
8067
8069
  selected = false,
8068
8070
  onClick,
@@ -8095,6 +8097,23 @@ function ChoiceButton({
8095
8097
  ]
8096
8098
  }
8097
8099
  ),
8100
+ assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
8101
+ "img",
8102
+ {
8103
+ src: assetUrl,
8104
+ alt: "",
8105
+ width: 16,
8106
+ height: 16,
8107
+ style: { imageRendering: "pixelated", objectFit: "contain" },
8108
+ className: "flex-shrink-0"
8109
+ }
8110
+ ) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
8111
+ const I = resolveIcon(icon);
8112
+ return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" }) : null;
8113
+ })() : /* @__PURE__ */ (() => {
8114
+ const I = icon;
8115
+ return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" });
8116
+ })() }) : null,
8098
8117
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm leading-snug", children: text })
8099
8118
  ]
8100
8119
  }
@@ -8103,6 +8122,7 @@ function ChoiceButton({
8103
8122
  var init_ChoiceButton = __esm({
8104
8123
  "components/game/atoms/ChoiceButton.tsx"() {
8105
8124
  init_cn();
8125
+ init_Icon();
8106
8126
  ChoiceButton.displayName = "ChoiceButton";
8107
8127
  }
8108
8128
  });
@@ -10984,16 +11004,26 @@ var init_useUnitSpriteAtlas = __esm({
10984
11004
  });
10985
11005
 
10986
11006
  // components/game/organisms/utils/isometric.ts
10987
- function isoToScreen(tileX, tileY, scale, baseOffsetX) {
11007
+ function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
10988
11008
  const scaledTileWidth = TILE_WIDTH * scale;
10989
11009
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
11010
+ if (layout === "hex") {
11011
+ const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
11012
+ const screenY2 = tileY * (scaledFloorHeight * 0.75);
11013
+ return { x: screenX2, y: screenY2 };
11014
+ }
10990
11015
  const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
10991
11016
  const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
10992
11017
  return { x: screenX, y: screenY };
10993
11018
  }
10994
- function screenToIso(screenX, screenY, scale, baseOffsetX) {
11019
+ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
10995
11020
  const scaledTileWidth = TILE_WIDTH * scale;
10996
11021
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
11022
+ if (layout === "hex") {
11023
+ const row = Math.round(screenY / (scaledFloorHeight * 0.75));
11024
+ const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
11025
+ return { x: col, y: row };
11026
+ }
10997
11027
  const adjustedX = screenX - baseOffsetX;
10998
11028
  const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
10999
11029
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
@@ -11043,6 +11073,7 @@ function IsometricCanvas({
11043
11073
  tileHoverEvent,
11044
11074
  tileLeaveEvent,
11045
11075
  // Rendering options
11076
+ tileLayout = "isometric",
11046
11077
  scale = 0.4,
11047
11078
  debug: debug2 = false,
11048
11079
  backgroundImage = "",
@@ -11112,13 +11143,17 @@ function IsometricCanvas({
11112
11143
  );
11113
11144
  const sortedTiles = React84.useMemo(() => {
11114
11145
  const tiles = [...tilesProp];
11115
- tiles.sort((a, b) => {
11116
- const depthA = a.x + a.y;
11117
- const depthB = b.x + b.y;
11118
- return depthA !== depthB ? depthA - depthB : a.y - b.y;
11119
- });
11146
+ if (tileLayout === "hex") {
11147
+ tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
11148
+ } else {
11149
+ tiles.sort((a, b) => {
11150
+ const depthA = a.x + a.y;
11151
+ const depthB = b.x + b.y;
11152
+ return depthA !== depthB ? depthA - depthB : a.y - b.y;
11153
+ });
11154
+ }
11120
11155
  return tiles;
11121
- }, [tilesProp]);
11156
+ }, [tilesProp, tileLayout]);
11122
11157
  const gridWidth = React84.useMemo(() => {
11123
11158
  if (sortedTiles.length === 0) return 0;
11124
11159
  return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
@@ -11232,18 +11267,19 @@ function IsometricCanvas({
11232
11267
  miniCanvas.width = mW;
11233
11268
  miniCanvas.height = mH;
11234
11269
  mCtx.clearRect(0, 0, mW, mH);
11235
- const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
11270
+ const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
11236
11271
  const minX = Math.min(...allScreenPos.map((p2) => p2.x));
11237
11272
  const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
11238
11273
  const minY = Math.min(...allScreenPos.map((p2) => p2.y));
11239
- const maxY = Math.max(...allScreenPos.map((p2) => p2.y + scaledTileHeight));
11274
+ const tileBottomExtent = tileLayout === "hex" ? scaledTileWidth : scaledTileHeight;
11275
+ const maxY = Math.max(...allScreenPos.map((p2) => p2.y + tileBottomExtent));
11240
11276
  const worldW = maxX - minX;
11241
11277
  const worldH = maxY - minY;
11242
11278
  const scaleM = Math.min(mW / worldW, mH / worldH) * 0.9;
11243
11279
  const offsetMx = (mW - worldW * scaleM) / 2;
11244
11280
  const offsetMy = (mH - worldH * scaleM) / 2;
11245
11281
  for (const tile of sortedTiles) {
11246
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
11282
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
11247
11283
  const mx = (pos.x - minX) * scaleM + offsetMx;
11248
11284
  const my = (pos.y - minY) * scaleM + offsetMy;
11249
11285
  const mTileW = scaledTileWidth * scaleM;
@@ -11259,7 +11295,7 @@ function IsometricCanvas({
11259
11295
  }
11260
11296
  for (const unit of units) {
11261
11297
  if (!unit.position) continue;
11262
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11298
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11263
11299
  const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
11264
11300
  const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
11265
11301
  mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
@@ -11275,7 +11311,7 @@ function IsometricCanvas({
11275
11311
  mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
11276
11312
  mCtx.lineWidth = 1;
11277
11313
  mCtx.strokeRect(vLeft, vTop, vW, vH);
11278
- }, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
11314
+ }, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
11279
11315
  const draw = React84.useCallback((animTime) => {
11280
11316
  const canvas = canvasRef.current;
11281
11317
  if (!canvas) return;
@@ -11315,7 +11351,7 @@ function IsometricCanvas({
11315
11351
  const visTop = cam.y - viewportSize.height / cam.zoom;
11316
11352
  const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
11317
11353
  for (const tile of sortedTiles) {
11318
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
11354
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
11319
11355
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11320
11356
  continue;
11321
11357
  }
@@ -11328,7 +11364,7 @@ function IsometricCanvas({
11328
11364
  const drawW = scaledTileWidth;
11329
11365
  const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
11330
11366
  const drawX = pos.x;
11331
- const drawY = pos.y + scaledTileHeight - drawH;
11367
+ const drawY = tileLayout === "hex" ? pos.y : pos.y + scaledTileHeight - drawH;
11332
11368
  ctx.drawImage(img, drawX, drawY, drawW, drawH);
11333
11369
  }
11334
11370
  } else {
@@ -11395,12 +11431,13 @@ function IsometricCanvas({
11395
11431
  }
11396
11432
  }
11397
11433
  const sortedFeatures = [...features].sort((a, b) => {
11434
+ if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
11398
11435
  const depthA = a.x + a.y;
11399
11436
  const depthB = b.x + b.y;
11400
11437
  return depthA !== depthB ? depthA - depthB : a.y - b.y;
11401
11438
  });
11402
11439
  for (const feature of sortedFeatures) {
11403
- const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
11440
+ const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
11404
11441
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11405
11442
  continue;
11406
11443
  }
@@ -11435,12 +11472,13 @@ function IsometricCanvas({
11435
11472
  }
11436
11473
  const unitsWithPosition = units.filter((u) => !!u.position);
11437
11474
  const sortedUnits = [...unitsWithPosition].sort((a, b) => {
11475
+ if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
11438
11476
  const depthA = a.position.x + a.position.y;
11439
11477
  const depthB = b.position.x + b.position.y;
11440
11478
  return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
11441
11479
  });
11442
11480
  for (const unit of sortedUnits) {
11443
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11481
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11444
11482
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11445
11483
  continue;
11446
11484
  }
@@ -11460,7 +11498,7 @@ function IsometricCanvas({
11460
11498
  drawH = maxUnitW / ar;
11461
11499
  }
11462
11500
  if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
11463
- const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
11501
+ const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
11464
11502
  const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
11465
11503
  const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
11466
11504
  ctx.save();
@@ -11589,6 +11627,7 @@ function IsometricCanvas({
11589
11627
  units,
11590
11628
  features,
11591
11629
  selectedUnitId,
11630
+ tileLayout,
11592
11631
  scale,
11593
11632
  debug2,
11594
11633
  resolveTerrainSpriteUrl,
@@ -11617,14 +11656,14 @@ function IsometricCanvas({
11617
11656
  if (!selectedUnitId) return;
11618
11657
  const unit = units.find((u) => u.id === selectedUnitId);
11619
11658
  if (!unit?.position) return;
11620
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
11659
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
11621
11660
  const centerX = pos.x + scaledTileWidth / 2;
11622
11661
  const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
11623
11662
  targetCameraRef.current = {
11624
11663
  x: centerX - viewportSize.width / 2,
11625
11664
  y: centerY - viewportSize.height / 2
11626
11665
  };
11627
- }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11666
+ }, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11628
11667
  React84.useEffect(() => {
11629
11668
  const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
11630
11669
  draw(animTimeRef.current);
@@ -11657,13 +11696,13 @@ function IsometricCanvas({
11657
11696
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
11658
11697
  const adjustedX = world.x - scaledTileWidth / 2;
11659
11698
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
11660
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
11699
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
11661
11700
  const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
11662
11701
  if (tileExists) {
11663
11702
  if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
11664
11703
  onTileHover?.(isoPos.x, isoPos.y);
11665
11704
  }
11666
- }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
11705
+ }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
11667
11706
  const handleCanvasPointerUp = React84.useCallback((e) => {
11668
11707
  singlePointerActiveRef.current = false;
11669
11708
  if (enableCamera) handlePointerUp();
@@ -11672,7 +11711,7 @@ function IsometricCanvas({
11672
11711
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
11673
11712
  const adjustedX = world.x - scaledTileWidth / 2;
11674
11713
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
11675
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
11714
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
11676
11715
  const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
11677
11716
  if (clickedUnit && (onUnitClick || unitClickEvent)) {
11678
11717
  if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
@@ -11684,7 +11723,7 @@ function IsometricCanvas({
11684
11723
  onTileClick?.(isoPos.x, isoPos.y);
11685
11724
  }
11686
11725
  }
11687
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
11726
+ }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
11688
11727
  const handleCanvasPointerLeave = React84.useCallback(() => {
11689
11728
  handleMouseLeave();
11690
11729
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -28077,6 +28116,7 @@ function PowerupSlots({
28077
28116
  /* @__PURE__ */ jsxRuntime.jsx(
28078
28117
  ItemSlot,
28079
28118
  {
28119
+ assetUrl: powerup.assetUrl,
28080
28120
  icon: powerup.icon,
28081
28121
  label: powerup.label,
28082
28122
  rarity: "uncommon",
@@ -28326,13 +28366,26 @@ function HealthPanel({
28326
28366
  )
28327
28367
  }
28328
28368
  ),
28329
- effects && effects.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxRuntime.jsx(
28369
+ effects && effects.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28330
28370
  Badge,
28331
28371
  {
28332
28372
  variant: effectVariantMap[effect.variant ?? "neutral"],
28333
28373
  size: "sm",
28334
- icon: effect.icon,
28335
- children: effect.label
28374
+ icon: effect.assetUrl ? void 0 : effect.icon,
28375
+ children: [
28376
+ effect.assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
28377
+ "img",
28378
+ {
28379
+ src: effect.assetUrl,
28380
+ alt: "",
28381
+ width: 12,
28382
+ height: 12,
28383
+ style: { imageRendering: "pixelated", objectFit: "contain" },
28384
+ className: "flex-shrink-0 inline-block"
28385
+ }
28386
+ ),
28387
+ effect.label
28388
+ ]
28336
28389
  },
28337
28390
  i
28338
28391
  )) })
@@ -28515,15 +28568,28 @@ function TurnPanel({
28515
28568
  activeTeam
28516
28569
  }
28517
28570
  ),
28518
- 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(
28571
+ 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(
28519
28572
  Button,
28520
28573
  {
28521
28574
  variant: "ghost",
28522
28575
  size: "sm",
28523
28576
  disabled: action.disabled,
28524
- leftIcon: action.icon,
28577
+ leftIcon: action.assetUrl ? void 0 : action.icon,
28525
28578
  onClick: () => handleAction(action.event),
28526
- children: action.label
28579
+ children: [
28580
+ action.assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
28581
+ "img",
28582
+ {
28583
+ src: action.assetUrl,
28584
+ alt: "",
28585
+ width: 14,
28586
+ height: 14,
28587
+ style: { imageRendering: "pixelated", objectFit: "contain" },
28588
+ className: "flex-shrink-0"
28589
+ }
28590
+ ),
28591
+ action.label
28592
+ ]
28527
28593
  },
28528
28594
  i
28529
28595
  )) })
@@ -43439,9 +43505,9 @@ var init_GameCanvas3D2 = __esm({
43439
43505
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43440
43506
  const hasAtlas = unitAtlasUrl(unit) !== null;
43441
43507
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
43442
- const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
43443
- const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
43444
- const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
43508
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * gridConfig.cellSize;
43509
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * gridConfig.cellSize;
43510
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * gridConfig.cellSize;
43445
43511
  return /* @__PURE__ */ jsxRuntime.jsxs(
43446
43512
  "group",
43447
43513
  {
@@ -43488,7 +43554,7 @@ var init_GameCanvas3D2 = __esm({
43488
43554
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43489
43555
  ] })
43490
43556
  ] }),
43491
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
43557
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, billboardHeight, 0], children: [
43492
43558
  /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
43493
43559
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
43494
43560
  /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
@@ -43517,7 +43583,7 @@ var init_GameCanvas3D2 = __esm({
43517
43583
  }
43518
43584
  );
43519
43585
  },
43520
- [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
43586
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale, gridConfig]
43521
43587
  );
43522
43588
  const DefaultFeatureRenderer = React84.useCallback(
43523
43589
  ({
@@ -43605,7 +43671,7 @@ var init_GameCanvas3D2 = __esm({
43605
43671
  {
43606
43672
  ref: containerRef,
43607
43673
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
43608
- style: { height: "85vh" },
43674
+ style: { flex: "1 1 0", minHeight: "400px" },
43609
43675
  "data-orientation": orientation,
43610
43676
  "data-camera-mode": cameraMode,
43611
43677
  "data-overlay": overlay,
@@ -43905,13 +43971,39 @@ var init_GameBoard3D = __esm({
43905
43971
  GameBoard3D.displayName = "GameBoard3D";
43906
43972
  }
43907
43973
  });
43908
- var GameShell;
43974
+ function getSlotContentRenderer2() {
43975
+ if (_scr) return _scr;
43976
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
43977
+ _scr = mod.SlotContentRenderer;
43978
+ return _scr;
43979
+ }
43980
+ function resolveDescriptor(value, idPrefix) {
43981
+ if (value === null || value === void 0) return value;
43982
+ if (React84__namespace.default.isValidElement(value)) return value;
43983
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
43984
+ if (Array.isArray(value)) {
43985
+ return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React84__namespace.default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
43986
+ }
43987
+ if (typeof value === "object") {
43988
+ const rec = value;
43989
+ if (typeof rec.type === "string" && patterns.getComponentForPattern(rec.type) !== null) {
43990
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
43991
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
43992
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
43993
+ const SCR = getSlotContentRenderer2();
43994
+ return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
43995
+ }
43996
+ }
43997
+ return null;
43998
+ }
43999
+ var _scr, GameShell;
43909
44000
  var init_GameShell = __esm({
43910
44001
  "components/game/templates/GameShell.tsx"() {
43911
44002
  init_cn();
43912
44003
  init_Box();
43913
44004
  init_Stack();
43914
44005
  init_Typography();
44006
+ _scr = null;
43915
44007
  GameShell = ({
43916
44008
  appName = "Game",
43917
44009
  hud,
@@ -43960,7 +44052,7 @@ var init_GameShell = __esm({
43960
44052
  children: appName
43961
44053
  }
43962
44054
  ),
43963
- hud && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "game-shell__hud", children: hud })
44055
+ hud && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "game-shell__hud", children: resolveDescriptor(hud, "gs-hud") })
43964
44056
  ]
43965
44057
  }
43966
44058
  ),
@@ -43973,7 +44065,7 @@ var init_GameShell = __esm({
43973
44065
  overflow: "hidden",
43974
44066
  position: "relative"
43975
44067
  },
43976
- children
44068
+ children: resolveDescriptor(children, "gs-children")
43977
44069
  }
43978
44070
  )
43979
44071
  ]
@@ -43983,7 +44075,32 @@ var init_GameShell = __esm({
43983
44075
  GameShell.displayName = "GameShell";
43984
44076
  }
43985
44077
  });
43986
- var GameTemplate;
44078
+ function getSlotContentRenderer3() {
44079
+ if (_scr2) return _scr2;
44080
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
44081
+ _scr2 = mod.SlotContentRenderer;
44082
+ return _scr2;
44083
+ }
44084
+ function resolveDescriptor2(value, idPrefix) {
44085
+ if (value === null || value === void 0) return value;
44086
+ if (React84__namespace.default.isValidElement(value)) return value;
44087
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
44088
+ if (Array.isArray(value)) {
44089
+ return value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(React84__namespace.default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
44090
+ }
44091
+ if (typeof value === "object") {
44092
+ const rec = value;
44093
+ if (typeof rec.type === "string" && patterns.getComponentForPattern(rec.type) !== null) {
44094
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
44095
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
44096
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
44097
+ const SCR = getSlotContentRenderer3();
44098
+ return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
44099
+ }
44100
+ }
44101
+ return null;
44102
+ }
44103
+ var _scr2, GameTemplate;
43987
44104
  var init_GameTemplate = __esm({
43988
44105
  "components/game/templates/GameTemplate.tsx"() {
43989
44106
  init_cn();
@@ -43991,6 +44108,7 @@ var init_GameTemplate = __esm({
43991
44108
  init_Stack();
43992
44109
  init_Typography();
43993
44110
  init_Button();
44111
+ _scr2 = null;
43994
44112
  GameTemplate = ({
43995
44113
  entity,
43996
44114
  title = "Game",
@@ -44058,13 +44176,13 @@ var init_GameTemplate = __esm({
44058
44176
  fullWidth: true,
44059
44177
  className: "flex-1 bg-muted",
44060
44178
  children: [
44061
- children,
44179
+ resolveDescriptor2(children, "gt-children"),
44062
44180
  hud && /* @__PURE__ */ jsxRuntime.jsx(
44063
44181
  Box,
44064
44182
  {
44065
44183
  position: "absolute",
44066
44184
  className: "top-0 left-0 right-0 pointer-events-none",
44067
- children: /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
44185
+ children: /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: resolveDescriptor2(hud, "gt-hud") })
44068
44186
  }
44069
44187
  )
44070
44188
  ]
@@ -44089,7 +44207,7 @@ var init_GameTemplate = __esm({
44089
44207
  children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h6", children: "Debug Panel" })
44090
44208
  }
44091
44209
  ),
44092
- /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", children: debugPanel })
44210
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { padding: "md", children: resolveDescriptor2(debugPanel, "gt-debug") })
44093
44211
  ]
44094
44212
  }
44095
44213
  )
@@ -44259,6 +44377,48 @@ var init_HeroOrganism = __esm({
44259
44377
  _HeroClickInterceptor.displayName = "_HeroClickInterceptor";
44260
44378
  }
44261
44379
  });
44380
+ function HexStrategyBoard({
44381
+ tiles,
44382
+ units,
44383
+ features,
44384
+ assetManifest,
44385
+ assetBaseUrl,
44386
+ scale = 0.45,
44387
+ showMinimap = true,
44388
+ enableCamera = true,
44389
+ tileClickEvent,
44390
+ unitClickEvent,
44391
+ isLoading,
44392
+ error,
44393
+ className
44394
+ }) {
44395
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
44396
+ IsometricCanvas_default,
44397
+ {
44398
+ tileLayout: "hex",
44399
+ tiles,
44400
+ units,
44401
+ features,
44402
+ assetManifest,
44403
+ assetBaseUrl,
44404
+ scale,
44405
+ showMinimap,
44406
+ enableCamera,
44407
+ tileClickEvent,
44408
+ unitClickEvent,
44409
+ isLoading,
44410
+ error
44411
+ }
44412
+ ) });
44413
+ }
44414
+ var init_HexStrategyBoard = __esm({
44415
+ "components/game/organisms/HexStrategyBoard.tsx"() {
44416
+ "use client";
44417
+ init_cn();
44418
+ init_IsometricCanvas();
44419
+ HexStrategyBoard.displayName = "HexStrategyBoard";
44420
+ }
44421
+ });
44262
44422
  var LandingPageTemplate;
44263
44423
  var init_LandingPageTemplate = __esm({
44264
44424
  "components/marketing/templates/LandingPageTemplate.tsx"() {
@@ -52087,6 +52247,7 @@ var init_component_registry_generated = __esm({
52087
52247
  init_HealthPanel();
52088
52248
  init_HeroOrganism();
52089
52249
  init_HeroSection();
52250
+ init_HexStrategyBoard();
52090
52251
  init_Icon();
52091
52252
  init_InfiniteScrollSentinel();
52092
52253
  init_Input();
@@ -52423,6 +52584,7 @@ var init_component_registry_generated = __esm({
52423
52584
  "HealthPanel": HealthPanel,
52424
52585
  "HeroOrganism": HeroOrganism,
52425
52586
  "HeroSection": HeroSection,
52587
+ "HexStrategyBoard": HexStrategyBoard,
52426
52588
  "Icon": Icon,
52427
52589
  "InfiniteScrollSentinel": InfiniteScrollSentinel,
52428
52590
  "Input": Input,
@@ -52624,7 +52786,7 @@ function getSlotFallback(slot, config) {
52624
52786
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
52625
52787
  return /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { variant });
52626
52788
  }
52627
- function getComponentForPattern(patternType) {
52789
+ function getComponentForPattern3(patternType) {
52628
52790
  const mapping = patterns.getComponentForPattern(patternType);
52629
52791
  if (!mapping) {
52630
52792
  return null;
@@ -53255,7 +53417,8 @@ function SlotContentRenderer({
53255
53417
  entityDef = schemaCtx.entities.get(linkedEntity);
53256
53418
  }
53257
53419
  }
53258
- const PatternComponent = getComponentForPattern(content.pattern);
53420
+ const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
53421
+ const PatternComponent = getComponentForPattern3(content.pattern);
53259
53422
  if (PatternComponent) {
53260
53423
  const childrenConfig = content.props.children;
53261
53424
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -53353,6 +53516,7 @@ function SlotContentRenderer({
53353
53516
  "data-orb-entity": content.entity,
53354
53517
  "data-orb-path": myPath,
53355
53518
  "data-orb-pattern": content.pattern,
53519
+ "data-orb-orbital": orbitalName,
53356
53520
  children: renderedChildren !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(PatternComponent, { ...finalProps, children: renderedChildren }) : /* @__PURE__ */ jsxRuntime.jsx(PatternComponent, { ...finalProps })
53357
53521
  }
53358
53522
  );
@@ -53372,6 +53536,7 @@ function SlotContentRenderer({
53372
53536
  "data-orb-entity": content.entity,
53373
53537
  "data-orb-path": patternPath ?? "root",
53374
53538
  "data-orb-pattern": content.pattern,
53539
+ "data-orb-orbital": orbitalName,
53375
53540
  children: content.props.children ?? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "p-4 text-sm text-muted-foreground border border-dashed border-border rounded", children: [
53376
53541
  "Unknown pattern: ",
53377
53542
  content.pattern,
@@ -53621,7 +53786,7 @@ function resolveLambdaBindings(body, params, item, index) {
53621
53786
  return body;
53622
53787
  }
53623
53788
  var _slotContentRenderer2 = null;
53624
- function getSlotContentRenderer2() {
53789
+ function getSlotContentRenderer4() {
53625
53790
  if (_slotContentRenderer2) return _slotContentRenderer2;
53626
53791
  const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
53627
53792
  _slotContentRenderer2 = mod.SlotContentRenderer;
@@ -53637,7 +53802,7 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
53637
53802
  if (typeof record.type !== "string") {
53638
53803
  return null;
53639
53804
  }
53640
- const SlotContentRenderer2 = getSlotContentRenderer2();
53805
+ const SlotContentRenderer2 = getSlotContentRenderer4();
53641
53806
  const rawChildProps = {};
53642
53807
  for (const [k, v] of Object.entries(record)) {
53643
53808
  if (k !== "type") rawChildProps[k] = v;