@almadar/ui 5.64.0 → 5.65.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.
@@ -27,20 +27,32 @@ export declare const DIAMOND_TOP_Y = 374;
27
27
  * Feature type → fallback color mapping (when sprites not loaded).
28
28
  */
29
29
  export declare const FEATURE_COLORS: Record<string, string>;
30
+ /**
31
+ * Tile layout mode. 'isometric' = 2:1 diamond projection (default).
32
+ * 'hex' = pointy-top offset-row hex grid.
33
+ *
34
+ * Hex constants (at scale=1):
35
+ * w = TILE_WIDTH (256) — horizontal cell width
36
+ * h = FLOOR_HEIGHT (128) — vertical row stride (= w/2; hex row-to-row = h*0.75 = 96)
37
+ * Forward: screenX = col*w + (row&1)*(w/2) + baseOffsetX
38
+ * screenY = row * (h * 0.75)
39
+ * Inverse: row = round(screenY / (h*0.75)); col = round((screenX - (row&1)*(w/2) - baseOffsetX) / w)
40
+ */
41
+ export type TileLayout = 'isometric' | 'hex';
30
42
  /**
31
43
  * Convert tile grid coordinates to screen pixel coordinates.
32
44
  *
33
- * Uses 2:1 diamond isometric projection:
34
- * - X increases to the lower-right
35
- * - Y increases to the lower-left
45
+ * For 'isometric' (default): 2:1 diamond projection.
46
+ * For 'hex': pointy-top offset-row projection (odd rows shifted right by w/2).
36
47
  *
37
- * @param tileX - Grid X coordinate
38
- * @param tileY - Grid Y coordinate
48
+ * @param tileX - Grid X (col) coordinate
49
+ * @param tileY - Grid Y (row) coordinate
39
50
  * @param scale - Render scale factor
40
51
  * @param baseOffsetX - Horizontal offset to center the grid
52
+ * @param layout - Tile layout mode (default: 'isometric')
41
53
  * @returns Screen position { x, y } of the tile's top-left corner
42
54
  */
43
- export declare function isoToScreen(tileX: number, tileY: number, scale: number, baseOffsetX: number): {
55
+ export declare function isoToScreen(tileX: number, tileY: number, scale: number, baseOffsetX: number, layout?: TileLayout): {
44
56
  x: number;
45
57
  y: number;
46
58
  };
@@ -53,9 +65,10 @@ export declare function isoToScreen(tileX: number, tileY: number, scale: number,
53
65
  * @param screenY - Screen Y in pixels
54
66
  * @param scale - Render scale factor
55
67
  * @param baseOffsetX - Horizontal offset used in isoToScreen
68
+ * @param layout - Tile layout mode (default: 'isometric')
56
69
  * @returns Snapped grid position { x, y }
57
70
  */
58
- export declare function screenToIso(screenX: number, screenY: number, scale: number, baseOffsetX: number): {
71
+ export declare function screenToIso(screenX: number, screenY: number, scale: number, baseOffsetX: number, layout?: TileLayout): {
59
72
  x: number;
60
73
  y: number;
61
74
  };
@@ -9923,16 +9923,26 @@ var init_useUnitSpriteAtlas = __esm({
9923
9923
  });
9924
9924
 
9925
9925
  // components/game/organisms/utils/isometric.ts
9926
- function isoToScreen(tileX, tileY, scale, baseOffsetX) {
9926
+ function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
9927
9927
  const scaledTileWidth = exports.TILE_WIDTH * scale;
9928
9928
  const scaledFloorHeight = exports.FLOOR_HEIGHT * scale;
9929
+ if (layout === "hex") {
9930
+ const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
9931
+ const screenY2 = tileY * (scaledFloorHeight * 0.75);
9932
+ return { x: screenX2, y: screenY2 };
9933
+ }
9929
9934
  const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
9930
9935
  const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
9931
9936
  return { x: screenX, y: screenY };
9932
9937
  }
9933
- function screenToIso(screenX, screenY, scale, baseOffsetX) {
9938
+ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
9934
9939
  const scaledTileWidth = exports.TILE_WIDTH * scale;
9935
9940
  const scaledFloorHeight = exports.FLOOR_HEIGHT * scale;
9941
+ if (layout === "hex") {
9942
+ const row = Math.round(screenY / (scaledFloorHeight * 0.75));
9943
+ const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
9944
+ return { x: col, y: row };
9945
+ }
9936
9946
  const adjustedX = screenX - baseOffsetX;
9937
9947
  const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
9938
9948
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
@@ -9982,6 +9992,7 @@ function IsometricCanvas({
9982
9992
  tileHoverEvent,
9983
9993
  tileLeaveEvent,
9984
9994
  // Rendering options
9995
+ tileLayout = "isometric",
9985
9996
  scale = 0.4,
9986
9997
  debug: debug2 = false,
9987
9998
  backgroundImage = "",
@@ -10051,13 +10062,17 @@ function IsometricCanvas({
10051
10062
  );
10052
10063
  const sortedTiles = React79.useMemo(() => {
10053
10064
  const tiles = [...tilesProp];
10054
- tiles.sort((a, b) => {
10055
- const depthA = a.x + a.y;
10056
- const depthB = b.x + b.y;
10057
- return depthA !== depthB ? depthA - depthB : a.y - b.y;
10058
- });
10065
+ if (tileLayout === "hex") {
10066
+ tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
10067
+ } else {
10068
+ tiles.sort((a, b) => {
10069
+ const depthA = a.x + a.y;
10070
+ const depthB = b.x + b.y;
10071
+ return depthA !== depthB ? depthA - depthB : a.y - b.y;
10072
+ });
10073
+ }
10059
10074
  return tiles;
10060
- }, [tilesProp]);
10075
+ }, [tilesProp, tileLayout]);
10061
10076
  const gridWidth = React79.useMemo(() => {
10062
10077
  if (sortedTiles.length === 0) return 0;
10063
10078
  return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
@@ -10171,7 +10186,7 @@ function IsometricCanvas({
10171
10186
  miniCanvas.width = mW;
10172
10187
  miniCanvas.height = mH;
10173
10188
  mCtx.clearRect(0, 0, mW, mH);
10174
- const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
10189
+ const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
10175
10190
  const minX = Math.min(...allScreenPos.map((p2) => p2.x));
10176
10191
  const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
10177
10192
  const minY = Math.min(...allScreenPos.map((p2) => p2.y));
@@ -10182,7 +10197,7 @@ function IsometricCanvas({
10182
10197
  const offsetMx = (mW - worldW * scaleM) / 2;
10183
10198
  const offsetMy = (mH - worldH * scaleM) / 2;
10184
10199
  for (const tile of sortedTiles) {
10185
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
10200
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
10186
10201
  const mx = (pos.x - minX) * scaleM + offsetMx;
10187
10202
  const my = (pos.y - minY) * scaleM + offsetMy;
10188
10203
  const mTileW = scaledTileWidth * scaleM;
@@ -10198,7 +10213,7 @@ function IsometricCanvas({
10198
10213
  }
10199
10214
  for (const unit of units) {
10200
10215
  if (!unit.position) continue;
10201
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
10216
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
10202
10217
  const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
10203
10218
  const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
10204
10219
  mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
@@ -10214,7 +10229,7 @@ function IsometricCanvas({
10214
10229
  mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
10215
10230
  mCtx.lineWidth = 1;
10216
10231
  mCtx.strokeRect(vLeft, vTop, vW, vH);
10217
- }, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
10232
+ }, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
10218
10233
  const draw = React79.useCallback((animTime) => {
10219
10234
  const canvas = canvasRef.current;
10220
10235
  if (!canvas) return;
@@ -10254,7 +10269,7 @@ function IsometricCanvas({
10254
10269
  const visTop = cam.y - viewportSize.height / cam.zoom;
10255
10270
  const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
10256
10271
  for (const tile of sortedTiles) {
10257
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
10272
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
10258
10273
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10259
10274
  continue;
10260
10275
  }
@@ -10334,12 +10349,13 @@ function IsometricCanvas({
10334
10349
  }
10335
10350
  }
10336
10351
  const sortedFeatures = [...features].sort((a, b) => {
10352
+ if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
10337
10353
  const depthA = a.x + a.y;
10338
10354
  const depthB = b.x + b.y;
10339
10355
  return depthA !== depthB ? depthA - depthB : a.y - b.y;
10340
10356
  });
10341
10357
  for (const feature of sortedFeatures) {
10342
- const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
10358
+ const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
10343
10359
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10344
10360
  continue;
10345
10361
  }
@@ -10374,12 +10390,13 @@ function IsometricCanvas({
10374
10390
  }
10375
10391
  const unitsWithPosition = units.filter((u) => !!u.position);
10376
10392
  const sortedUnits = [...unitsWithPosition].sort((a, b) => {
10393
+ if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
10377
10394
  const depthA = a.position.x + a.position.y;
10378
10395
  const depthB = b.position.x + b.position.y;
10379
10396
  return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
10380
10397
  });
10381
10398
  for (const unit of sortedUnits) {
10382
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
10399
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
10383
10400
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10384
10401
  continue;
10385
10402
  }
@@ -10399,7 +10416,7 @@ function IsometricCanvas({
10399
10416
  drawH = maxUnitW / ar;
10400
10417
  }
10401
10418
  if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
10402
- const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
10419
+ const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
10403
10420
  const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
10404
10421
  const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
10405
10422
  ctx.save();
@@ -10528,6 +10545,7 @@ function IsometricCanvas({
10528
10545
  units,
10529
10546
  features,
10530
10547
  selectedUnitId,
10548
+ tileLayout,
10531
10549
  scale,
10532
10550
  debug2,
10533
10551
  resolveTerrainSpriteUrl,
@@ -10556,14 +10574,14 @@ function IsometricCanvas({
10556
10574
  if (!selectedUnitId) return;
10557
10575
  const unit = units.find((u) => u.id === selectedUnitId);
10558
10576
  if (!unit?.position) return;
10559
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
10577
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
10560
10578
  const centerX = pos.x + scaledTileWidth / 2;
10561
10579
  const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
10562
10580
  targetCameraRef.current = {
10563
10581
  x: centerX - viewportSize.width / 2,
10564
10582
  y: centerY - viewportSize.height / 2
10565
10583
  };
10566
- }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
10584
+ }, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
10567
10585
  React79.useEffect(() => {
10568
10586
  const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
10569
10587
  draw(animTimeRef.current);
@@ -10596,13 +10614,13 @@ function IsometricCanvas({
10596
10614
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10597
10615
  const adjustedX = world.x - scaledTileWidth / 2;
10598
10616
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10599
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
10617
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
10600
10618
  const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
10601
10619
  if (tileExists) {
10602
10620
  if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
10603
10621
  onTileHover?.(isoPos.x, isoPos.y);
10604
10622
  }
10605
- }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
10623
+ }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
10606
10624
  const handleCanvasPointerUp = React79.useCallback((e) => {
10607
10625
  singlePointerActiveRef.current = false;
10608
10626
  if (enableCamera) handlePointerUp();
@@ -10611,7 +10629,7 @@ function IsometricCanvas({
10611
10629
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10612
10630
  const adjustedX = world.x - scaledTileWidth / 2;
10613
10631
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10614
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
10632
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
10615
10633
  const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
10616
10634
  if (clickedUnit && (onUnitClick || unitClickEvent)) {
10617
10635
  if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
@@ -10623,7 +10641,7 @@ function IsometricCanvas({
10623
10641
  onTileClick?.(isoPos.x, isoPos.y);
10624
10642
  }
10625
10643
  }
10626
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
10644
+ }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
10627
10645
  const handleCanvasPointerLeave = React79.useCallback(() => {
10628
10646
  handleMouseLeave();
10629
10647
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -45314,6 +45332,48 @@ var init_HeroOrganism = __esm({
45314
45332
  _HeroClickInterceptor.displayName = "_HeroClickInterceptor";
45315
45333
  }
45316
45334
  });
45335
+ function HexStrategyBoard({
45336
+ tiles,
45337
+ units,
45338
+ features,
45339
+ assetManifest,
45340
+ assetBaseUrl,
45341
+ scale = 0.45,
45342
+ showMinimap = true,
45343
+ enableCamera = true,
45344
+ tileClickEvent,
45345
+ unitClickEvent,
45346
+ isLoading,
45347
+ error,
45348
+ className
45349
+ }) {
45350
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
45351
+ IsometricCanvas_default,
45352
+ {
45353
+ tileLayout: "hex",
45354
+ tiles,
45355
+ units,
45356
+ features,
45357
+ assetManifest,
45358
+ assetBaseUrl,
45359
+ scale,
45360
+ showMinimap,
45361
+ enableCamera,
45362
+ tileClickEvent,
45363
+ unitClickEvent,
45364
+ isLoading,
45365
+ error
45366
+ }
45367
+ ) });
45368
+ }
45369
+ var init_HexStrategyBoard = __esm({
45370
+ "components/game/organisms/HexStrategyBoard.tsx"() {
45371
+ "use client";
45372
+ init_cn();
45373
+ init_IsometricCanvas();
45374
+ HexStrategyBoard.displayName = "HexStrategyBoard";
45375
+ }
45376
+ });
45317
45377
  exports.LandingPageTemplate = void 0;
45318
45378
  var init_LandingPageTemplate = __esm({
45319
45379
  "components/marketing/templates/LandingPageTemplate.tsx"() {
@@ -53622,6 +53682,7 @@ var init_component_registry_generated = __esm({
53622
53682
  init_HealthPanel();
53623
53683
  init_HeroOrganism();
53624
53684
  init_HeroSection();
53685
+ init_HexStrategyBoard();
53625
53686
  init_Icon();
53626
53687
  init_InfiniteScrollSentinel();
53627
53688
  init_Input();
@@ -53958,6 +54019,7 @@ var init_component_registry_generated = __esm({
53958
54019
  "HealthPanel": HealthPanel,
53959
54020
  "HeroOrganism": exports.HeroOrganism,
53960
54021
  "HeroSection": exports.HeroSection,
54022
+ "HexStrategyBoard": HexStrategyBoard,
53961
54023
  "Icon": exports.Icon,
53962
54024
  "InfiniteScrollSentinel": exports.InfiniteScrollSentinel,
53963
54025
  "Input": exports.Input,
@@ -55603,6 +55665,7 @@ init_CityBuilderBoard();
55603
55665
  init_GameBoard3D();
55604
55666
  init_VisualNovelBoard();
55605
55667
  init_CardBattlerBoard();
55668
+ init_HexStrategyBoard();
55606
55669
  init_TraitStateViewer();
55607
55670
  init_TraitSlot();
55608
55671
 
@@ -56244,6 +56307,7 @@ exports.GameMenu = GameMenu;
56244
56307
  exports.GameOverScreen = GameOverScreen;
56245
56308
  exports.HealthBar = HealthBar;
56246
56309
  exports.HealthPanel = HealthPanel;
56310
+ exports.HexStrategyBoard = HexStrategyBoard;
56247
56311
  exports.InventoryGrid = InventoryGrid;
56248
56312
  exports.InventoryPanel = InventoryPanel;
56249
56313
  exports.IsometricCanvas = IsometricCanvas;
@@ -9877,16 +9877,26 @@ var init_useUnitSpriteAtlas = __esm({
9877
9877
  });
9878
9878
 
9879
9879
  // components/game/organisms/utils/isometric.ts
9880
- function isoToScreen(tileX, tileY, scale, baseOffsetX) {
9880
+ function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
9881
9881
  const scaledTileWidth = TILE_WIDTH * scale;
9882
9882
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
9883
+ if (layout === "hex") {
9884
+ const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
9885
+ const screenY2 = tileY * (scaledFloorHeight * 0.75);
9886
+ return { x: screenX2, y: screenY2 };
9887
+ }
9883
9888
  const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
9884
9889
  const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
9885
9890
  return { x: screenX, y: screenY };
9886
9891
  }
9887
- function screenToIso(screenX, screenY, scale, baseOffsetX) {
9892
+ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
9888
9893
  const scaledTileWidth = TILE_WIDTH * scale;
9889
9894
  const scaledFloorHeight = FLOOR_HEIGHT * scale;
9895
+ if (layout === "hex") {
9896
+ const row = Math.round(screenY / (scaledFloorHeight * 0.75));
9897
+ const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
9898
+ return { x: col, y: row };
9899
+ }
9890
9900
  const adjustedX = screenX - baseOffsetX;
9891
9901
  const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
9892
9902
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
@@ -9936,6 +9946,7 @@ function IsometricCanvas({
9936
9946
  tileHoverEvent,
9937
9947
  tileLeaveEvent,
9938
9948
  // Rendering options
9949
+ tileLayout = "isometric",
9939
9950
  scale = 0.4,
9940
9951
  debug: debug2 = false,
9941
9952
  backgroundImage = "",
@@ -10005,13 +10016,17 @@ function IsometricCanvas({
10005
10016
  );
10006
10017
  const sortedTiles = useMemo(() => {
10007
10018
  const tiles = [...tilesProp];
10008
- tiles.sort((a, b) => {
10009
- const depthA = a.x + a.y;
10010
- const depthB = b.x + b.y;
10011
- return depthA !== depthB ? depthA - depthB : a.y - b.y;
10012
- });
10019
+ if (tileLayout === "hex") {
10020
+ tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
10021
+ } else {
10022
+ tiles.sort((a, b) => {
10023
+ const depthA = a.x + a.y;
10024
+ const depthB = b.x + b.y;
10025
+ return depthA !== depthB ? depthA - depthB : a.y - b.y;
10026
+ });
10027
+ }
10013
10028
  return tiles;
10014
- }, [tilesProp]);
10029
+ }, [tilesProp, tileLayout]);
10015
10030
  const gridWidth = useMemo(() => {
10016
10031
  if (sortedTiles.length === 0) return 0;
10017
10032
  return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
@@ -10125,7 +10140,7 @@ function IsometricCanvas({
10125
10140
  miniCanvas.width = mW;
10126
10141
  miniCanvas.height = mH;
10127
10142
  mCtx.clearRect(0, 0, mW, mH);
10128
- const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
10143
+ const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
10129
10144
  const minX = Math.min(...allScreenPos.map((p2) => p2.x));
10130
10145
  const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
10131
10146
  const minY = Math.min(...allScreenPos.map((p2) => p2.y));
@@ -10136,7 +10151,7 @@ function IsometricCanvas({
10136
10151
  const offsetMx = (mW - worldW * scaleM) / 2;
10137
10152
  const offsetMy = (mH - worldH * scaleM) / 2;
10138
10153
  for (const tile of sortedTiles) {
10139
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
10154
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
10140
10155
  const mx = (pos.x - minX) * scaleM + offsetMx;
10141
10156
  const my = (pos.y - minY) * scaleM + offsetMy;
10142
10157
  const mTileW = scaledTileWidth * scaleM;
@@ -10152,7 +10167,7 @@ function IsometricCanvas({
10152
10167
  }
10153
10168
  for (const unit of units) {
10154
10169
  if (!unit.position) continue;
10155
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
10170
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
10156
10171
  const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
10157
10172
  const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
10158
10173
  mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
@@ -10168,7 +10183,7 @@ function IsometricCanvas({
10168
10183
  mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
10169
10184
  mCtx.lineWidth = 1;
10170
10185
  mCtx.strokeRect(vLeft, vTop, vW, vH);
10171
- }, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
10186
+ }, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
10172
10187
  const draw = useCallback((animTime) => {
10173
10188
  const canvas = canvasRef.current;
10174
10189
  if (!canvas) return;
@@ -10208,7 +10223,7 @@ function IsometricCanvas({
10208
10223
  const visTop = cam.y - viewportSize.height / cam.zoom;
10209
10224
  const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
10210
10225
  for (const tile of sortedTiles) {
10211
- const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
10226
+ const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
10212
10227
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10213
10228
  continue;
10214
10229
  }
@@ -10288,12 +10303,13 @@ function IsometricCanvas({
10288
10303
  }
10289
10304
  }
10290
10305
  const sortedFeatures = [...features].sort((a, b) => {
10306
+ if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
10291
10307
  const depthA = a.x + a.y;
10292
10308
  const depthB = b.x + b.y;
10293
10309
  return depthA !== depthB ? depthA - depthB : a.y - b.y;
10294
10310
  });
10295
10311
  for (const feature of sortedFeatures) {
10296
- const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
10312
+ const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
10297
10313
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10298
10314
  continue;
10299
10315
  }
@@ -10328,12 +10344,13 @@ function IsometricCanvas({
10328
10344
  }
10329
10345
  const unitsWithPosition = units.filter((u) => !!u.position);
10330
10346
  const sortedUnits = [...unitsWithPosition].sort((a, b) => {
10347
+ if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
10331
10348
  const depthA = a.position.x + a.position.y;
10332
10349
  const depthB = b.position.x + b.position.y;
10333
10350
  return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
10334
10351
  });
10335
10352
  for (const unit of sortedUnits) {
10336
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
10353
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
10337
10354
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10338
10355
  continue;
10339
10356
  }
@@ -10353,7 +10370,7 @@ function IsometricCanvas({
10353
10370
  drawH = maxUnitW / ar;
10354
10371
  }
10355
10372
  if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
10356
- const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
10373
+ const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
10357
10374
  const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
10358
10375
  const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
10359
10376
  ctx.save();
@@ -10482,6 +10499,7 @@ function IsometricCanvas({
10482
10499
  units,
10483
10500
  features,
10484
10501
  selectedUnitId,
10502
+ tileLayout,
10485
10503
  scale,
10486
10504
  debug2,
10487
10505
  resolveTerrainSpriteUrl,
@@ -10510,14 +10528,14 @@ function IsometricCanvas({
10510
10528
  if (!selectedUnitId) return;
10511
10529
  const unit = units.find((u) => u.id === selectedUnitId);
10512
10530
  if (!unit?.position) return;
10513
- const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
10531
+ const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
10514
10532
  const centerX = pos.x + scaledTileWidth / 2;
10515
10533
  const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
10516
10534
  targetCameraRef.current = {
10517
10535
  x: centerX - viewportSize.width / 2,
10518
10536
  y: centerY - viewportSize.height / 2
10519
10537
  };
10520
- }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
10538
+ }, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
10521
10539
  useEffect(() => {
10522
10540
  const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
10523
10541
  draw(animTimeRef.current);
@@ -10550,13 +10568,13 @@ function IsometricCanvas({
10550
10568
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10551
10569
  const adjustedX = world.x - scaledTileWidth / 2;
10552
10570
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10553
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
10571
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
10554
10572
  const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
10555
10573
  if (tileExists) {
10556
10574
  if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
10557
10575
  onTileHover?.(isoPos.x, isoPos.y);
10558
10576
  }
10559
- }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
10577
+ }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
10560
10578
  const handleCanvasPointerUp = useCallback((e) => {
10561
10579
  singlePointerActiveRef.current = false;
10562
10580
  if (enableCamera) handlePointerUp();
@@ -10565,7 +10583,7 @@ function IsometricCanvas({
10565
10583
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10566
10584
  const adjustedX = world.x - scaledTileWidth / 2;
10567
10585
  const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10568
- const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
10586
+ const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
10569
10587
  const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
10570
10588
  if (clickedUnit && (onUnitClick || unitClickEvent)) {
10571
10589
  if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
@@ -10577,7 +10595,7 @@ function IsometricCanvas({
10577
10595
  onTileClick?.(isoPos.x, isoPos.y);
10578
10596
  }
10579
10597
  }
10580
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
10598
+ }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
10581
10599
  const handleCanvasPointerLeave = useCallback(() => {
10582
10600
  handleMouseLeave();
10583
10601
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -45268,6 +45286,48 @@ var init_HeroOrganism = __esm({
45268
45286
  _HeroClickInterceptor.displayName = "_HeroClickInterceptor";
45269
45287
  }
45270
45288
  });
45289
+ function HexStrategyBoard({
45290
+ tiles,
45291
+ units,
45292
+ features,
45293
+ assetManifest,
45294
+ assetBaseUrl,
45295
+ scale = 0.45,
45296
+ showMinimap = true,
45297
+ enableCamera = true,
45298
+ tileClickEvent,
45299
+ unitClickEvent,
45300
+ isLoading,
45301
+ error,
45302
+ className
45303
+ }) {
45304
+ return /* @__PURE__ */ jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsx(
45305
+ IsometricCanvas_default,
45306
+ {
45307
+ tileLayout: "hex",
45308
+ tiles,
45309
+ units,
45310
+ features,
45311
+ assetManifest,
45312
+ assetBaseUrl,
45313
+ scale,
45314
+ showMinimap,
45315
+ enableCamera,
45316
+ tileClickEvent,
45317
+ unitClickEvent,
45318
+ isLoading,
45319
+ error
45320
+ }
45321
+ ) });
45322
+ }
45323
+ var init_HexStrategyBoard = __esm({
45324
+ "components/game/organisms/HexStrategyBoard.tsx"() {
45325
+ "use client";
45326
+ init_cn();
45327
+ init_IsometricCanvas();
45328
+ HexStrategyBoard.displayName = "HexStrategyBoard";
45329
+ }
45330
+ });
45271
45331
  var LandingPageTemplate;
45272
45332
  var init_LandingPageTemplate = __esm({
45273
45333
  "components/marketing/templates/LandingPageTemplate.tsx"() {
@@ -53576,6 +53636,7 @@ var init_component_registry_generated = __esm({
53576
53636
  init_HealthPanel();
53577
53637
  init_HeroOrganism();
53578
53638
  init_HeroSection();
53639
+ init_HexStrategyBoard();
53579
53640
  init_Icon();
53580
53641
  init_InfiniteScrollSentinel();
53581
53642
  init_Input();
@@ -53912,6 +53973,7 @@ var init_component_registry_generated = __esm({
53912
53973
  "HealthPanel": HealthPanel,
53913
53974
  "HeroOrganism": HeroOrganism,
53914
53975
  "HeroSection": HeroSection,
53976
+ "HexStrategyBoard": HexStrategyBoard,
53915
53977
  "Icon": Icon,
53916
53978
  "InfiniteScrollSentinel": InfiniteScrollSentinel,
53917
53979
  "Input": Input,
@@ -55557,6 +55619,7 @@ init_CityBuilderBoard();
55557
55619
  init_GameBoard3D();
55558
55620
  init_VisualNovelBoard();
55559
55621
  init_CardBattlerBoard();
55622
+ init_HexStrategyBoard();
55560
55623
  init_TraitStateViewer();
55561
55624
  init_TraitSlot();
55562
55625
 
@@ -56144,4 +56207,4 @@ init_AboutPageTemplate();
56144
56207
  // components/index.ts
56145
56208
  init_cn();
56146
56209
 
56147
- export { ALL_PRESETS, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBattlerBoard, CardBattlerTemplate, CardBody, CardContent, CardFooter, CardGrid, CardHand, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, CityBuilderBoard, CityBuilderTemplate, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameBoard3D, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HealthPanel, HeroOrganism, HeroSection, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerBoard, PlatformerCanvas, PlatformerTemplate, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RoguelikeBoard, RoguelikeTemplate, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TopDownShooterBoard, TopDownShooterTemplate, TowerDefenseBoard, TowerDefenseTemplate, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VisualNovelBoard, VisualNovelTemplate, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, drawSprite, generateCombatMessage, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseLessonSegments, parseMarkdownWithCodeBlocks, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, toCodeLanguage, transitionAnimation, useAnchorRect, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };
56210
+ export { ALL_PRESETS, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBattlerBoard, CardBattlerTemplate, CardBody, CardContent, CardFooter, CardGrid, CardHand, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, CityBuilderBoard, CityBuilderTemplate, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameBoard3D, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HealthPanel, HeroOrganism, HeroSection, HexStrategyBoard, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerBoard, PlatformerCanvas, PlatformerTemplate, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RoguelikeBoard, RoguelikeTemplate, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TopDownShooterBoard, TopDownShooterTemplate, TowerDefenseBoard, TowerDefenseTemplate, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VisualNovelBoard, VisualNovelTemplate, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, drawSprite, generateCombatMessage, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseLessonSegments, parseMarkdownWithCodeBlocks, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, toCodeLanguage, transitionAnimation, useAnchorRect, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };