@almadar/ui 5.55.0 → 5.56.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.
@@ -9774,6 +9774,8 @@ function IsometricCanvas({
9774
9774
  showMinimap = true,
9775
9775
  enableCamera = true,
9776
9776
  unitScale = 1,
9777
+ spriteHeightRatio = 1.5,
9778
+ spriteMaxWidthRatio = 0.6,
9777
9779
  // Asset resolution
9778
9780
  getTerrainSprite,
9779
9781
  getFeatureSprite,
@@ -10165,8 +10167,8 @@ function IsometricCanvas({
10165
10167
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
10166
10168
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
10167
10169
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
10168
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
10169
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
10170
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
10171
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10170
10172
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
10171
10173
  let drawH = unitDrawH;
10172
10174
  let drawW = unitDrawH * ar;
@@ -10550,6 +10552,8 @@ function BattleBoard({
10550
10552
  assetManifest: propAssetManifest,
10551
10553
  scale = 0.45,
10552
10554
  unitScale = 1,
10555
+ spriteHeightRatio = 1.5,
10556
+ spriteMaxWidthRatio = 0.6,
10553
10557
  header,
10554
10558
  sidebar,
10555
10559
  actions,
@@ -10840,7 +10844,9 @@ function BattleBoard({
10840
10844
  hasActiveEffects: hasActiveEffects2,
10841
10845
  effectSpriteUrls,
10842
10846
  resolveUnitFrame,
10843
- unitScale
10847
+ unitScale,
10848
+ spriteHeightRatio,
10849
+ spriteMaxWidthRatio
10844
10850
  }
10845
10851
  ),
10846
10852
  overlay && overlay(ctx)
@@ -42926,6 +42932,8 @@ var init_GameCanvas3D2 = __esm({
42926
42932
  attackTargets = [],
42927
42933
  selectedTileIds = [],
42928
42934
  selectedUnitId = null,
42935
+ unitScale = 1,
42936
+ scale = 0.45,
42929
42937
  children
42930
42938
  }, ref) => {
42931
42939
  const containerRef = React76.useRef(null);
@@ -43142,12 +43150,18 @@ var init_GameCanvas3D2 = __esm({
43142
43150
  },
43143
43151
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
43144
43152
  );
43153
+ const UNIT_BASE_MODEL_SCALE = 0.5;
43154
+ const UNIT_BASE_BILLBOARD_HEIGHT = 1.2;
43155
+ const UNIT_BASE_PRIMITIVE_RADIUS = 0.3;
43145
43156
  const DefaultUnitRenderer = React76.useCallback(
43146
43157
  ({ unit, position }) => {
43147
43158
  const isSelected = selectedUnitId === unit.id;
43148
43159
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43149
43160
  const hasAtlas = unitAtlasUrl(unit) !== null;
43150
43161
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
43162
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
43163
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
43164
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
43151
43165
  return /* @__PURE__ */ jsxRuntime.jsxs(
43152
43166
  "group",
43153
43167
  {
@@ -43165,7 +43179,8 @@ var init_GameCanvas3D2 = __esm({
43165
43179
  UnitSpriteBillboard,
43166
43180
  {
43167
43181
  sheetUrl: initialFrame.sheetUrl,
43168
- resolveFrame: () => resolveUnitFrame(unit.id)
43182
+ resolveFrame: () => resolveUnitFrame(unit.id),
43183
+ height: billboardHeight
43169
43184
  }
43170
43185
  ) })
43171
43186
  ) : unit.modelUrl ? (
@@ -43174,22 +43189,22 @@ var init_GameCanvas3D2 = __esm({
43174
43189
  ModelLoader,
43175
43190
  {
43176
43191
  url: unit.modelUrl,
43177
- scale: 0.5,
43192
+ scale: modelScale,
43178
43193
  fallbackGeometry: "box",
43179
43194
  castShadow: true
43180
43195
  }
43181
43196
  )
43182
43197
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
43183
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
43184
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
43198
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius, 0], children: [
43199
+ /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [primitiveRadius, primitiveRadius, primitiveRadius * 0.33, 8] }),
43185
43200
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43186
43201
  ] }),
43187
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
43188
- /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
43202
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 2, 0], children: [
43203
+ /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [primitiveRadius * 0.67, primitiveRadius * 1.33, 4, 8] }),
43189
43204
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43190
43205
  ] }),
43191
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
43192
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
43206
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 3, 0], children: [
43207
+ /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [primitiveRadius * 0.4, 8, 8] }),
43193
43208
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43194
43209
  ] })
43195
43210
  ] }),
@@ -43222,7 +43237,7 @@ var init_GameCanvas3D2 = __esm({
43222
43237
  }
43223
43238
  );
43224
43239
  },
43225
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
43240
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
43226
43241
  );
43227
43242
  const DefaultFeatureRenderer = React76.useCallback(
43228
43243
  ({
@@ -43365,33 +43380,35 @@ var init_GameCanvas3D2 = __esm({
43365
43380
  fadeStrength: 1
43366
43381
  }
43367
43382
  ),
43368
- tiles.map((tile, index) => {
43369
- const position = gridToWorld(
43370
- tile.x,
43371
- tile.z ?? tile.y ?? 0,
43372
- tile.elevation ?? 0
43373
- );
43374
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
43375
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
43376
- }),
43377
- features.map((feature, index) => {
43378
- const position = gridToWorld(
43379
- feature.x,
43380
- feature.z ?? feature.y ?? 0,
43381
- (feature.elevation ?? 0) + 0.5
43382
- );
43383
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
43384
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
43385
- }),
43386
- units.map((unit) => {
43387
- const position = gridToWorld(
43388
- unit.x ?? 0,
43389
- unit.z ?? unit.y ?? 0,
43390
- (unit.elevation ?? 0) + 0.5
43391
- );
43392
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
43393
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
43394
- }),
43383
+ /* @__PURE__ */ jsxRuntime.jsxs("group", { scale, children: [
43384
+ tiles.map((tile, index) => {
43385
+ const position = gridToWorld(
43386
+ tile.x,
43387
+ tile.z ?? tile.y ?? 0,
43388
+ tile.elevation ?? 0
43389
+ );
43390
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
43391
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
43392
+ }),
43393
+ features.map((feature, index) => {
43394
+ const position = gridToWorld(
43395
+ feature.x,
43396
+ feature.z ?? feature.y ?? 0,
43397
+ (feature.elevation ?? 0) + 0.5
43398
+ );
43399
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
43400
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
43401
+ }),
43402
+ units.map((unit) => {
43403
+ const position = gridToWorld(
43404
+ unit.x ?? 0,
43405
+ unit.z ?? unit.y ?? 0,
43406
+ (unit.elevation ?? 0) + 0.5
43407
+ );
43408
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
43409
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
43410
+ })
43411
+ ] }),
43395
43412
  children,
43396
43413
  /* @__PURE__ */ jsxRuntime.jsx(
43397
43414
  drei.OrbitControls,
@@ -43434,6 +43451,8 @@ function GameBoard3D({
43434
43451
  features = [],
43435
43452
  cameraMode = "perspective",
43436
43453
  backgroundColor = "#2a1a1a",
43454
+ unitScale = 1,
43455
+ scale = 0.45,
43437
43456
  tileClickEvent,
43438
43457
  unitClickEvent,
43439
43458
  attackEvent,
@@ -43534,6 +43553,8 @@ function GameBoard3D({
43534
43553
  selectedUnitId,
43535
43554
  validMoves,
43536
43555
  attackTargets,
43556
+ unitScale,
43557
+ scale,
43537
43558
  className: "game-board-3d__canvas w-full min-h-[85vh]"
43538
43559
  }
43539
43560
  ),
@@ -45693,6 +45714,8 @@ function RoguelikeBoard({
45693
45714
  assetManifest: propAssetManifest,
45694
45715
  scale = 0.45,
45695
45716
  unitScale = 1,
45717
+ spriteHeightRatio = 1.5,
45718
+ spriteMaxWidthRatio = 0.6,
45696
45719
  moveEvent,
45697
45720
  playAgainEvent,
45698
45721
  gameEndEvent,
@@ -45840,7 +45863,9 @@ function RoguelikeBoard({
45840
45863
  scale,
45841
45864
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
45842
45865
  assetManifest: propAssetManifest,
45843
- unitScale
45866
+ unitScale,
45867
+ spriteHeightRatio,
45868
+ spriteMaxWidthRatio
45844
45869
  }
45845
45870
  ) }),
45846
45871
  !isGameOver && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -50434,6 +50459,9 @@ function TowerDefenseBoard({
50434
50459
  waveActive: propWaveActive,
50435
50460
  towerCost = 25,
50436
50461
  scale = 0.45,
50462
+ unitScale = 1,
50463
+ spriteHeightRatio = 1.5,
50464
+ spriteMaxWidthRatio = 0.6,
50437
50465
  placeTowerEvent,
50438
50466
  startWaveEvent,
50439
50467
  playAgainEvent,
@@ -50541,7 +50569,10 @@ function TowerDefenseBoard({
50541
50569
  onTileClick: handleTileClick,
50542
50570
  onTileHover: (x, y) => setHoveredTile({ x, y }),
50543
50571
  onTileLeave: () => setHoveredTile(null),
50544
- scale
50572
+ scale,
50573
+ unitScale,
50574
+ spriteHeightRatio,
50575
+ spriteMaxWidthRatio
50545
50576
  }
50546
50577
  ),
50547
50578
  hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
@@ -50877,6 +50908,8 @@ function WorldMapBoard({
50877
50908
  isLoading,
50878
50909
  scale = 0.4,
50879
50910
  unitScale = 2.5,
50911
+ spriteHeightRatio = 1.5,
50912
+ spriteMaxWidthRatio = 0.6,
50880
50913
  allowMoveAllHeroes = false,
50881
50914
  isInRange = defaultIsInRange,
50882
50915
  heroSelectEvent,
@@ -51114,6 +51147,8 @@ function WorldMapBoard({
51114
51147
  effectSpriteUrls,
51115
51148
  resolveUnitFrame,
51116
51149
  unitScale,
51150
+ spriteHeightRatio,
51151
+ spriteMaxWidthRatio,
51117
51152
  diamondTopY,
51118
51153
  enableCamera
51119
51154
  }
@@ -9728,6 +9728,8 @@ function IsometricCanvas({
9728
9728
  showMinimap = true,
9729
9729
  enableCamera = true,
9730
9730
  unitScale = 1,
9731
+ spriteHeightRatio = 1.5,
9732
+ spriteMaxWidthRatio = 0.6,
9731
9733
  // Asset resolution
9732
9734
  getTerrainSprite,
9733
9735
  getFeatureSprite,
@@ -10119,8 +10121,8 @@ function IsometricCanvas({
10119
10121
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
10120
10122
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
10121
10123
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
10122
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
10123
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
10124
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
10125
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10124
10126
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
10125
10127
  let drawH = unitDrawH;
10126
10128
  let drawW = unitDrawH * ar;
@@ -10504,6 +10506,8 @@ function BattleBoard({
10504
10506
  assetManifest: propAssetManifest,
10505
10507
  scale = 0.45,
10506
10508
  unitScale = 1,
10509
+ spriteHeightRatio = 1.5,
10510
+ spriteMaxWidthRatio = 0.6,
10507
10511
  header,
10508
10512
  sidebar,
10509
10513
  actions,
@@ -10794,7 +10798,9 @@ function BattleBoard({
10794
10798
  hasActiveEffects: hasActiveEffects2,
10795
10799
  effectSpriteUrls,
10796
10800
  resolveUnitFrame,
10797
- unitScale
10801
+ unitScale,
10802
+ spriteHeightRatio,
10803
+ spriteMaxWidthRatio
10798
10804
  }
10799
10805
  ),
10800
10806
  overlay && overlay(ctx)
@@ -42880,6 +42886,8 @@ var init_GameCanvas3D2 = __esm({
42880
42886
  attackTargets = [],
42881
42887
  selectedTileIds = [],
42882
42888
  selectedUnitId = null,
42889
+ unitScale = 1,
42890
+ scale = 0.45,
42883
42891
  children
42884
42892
  }, ref) => {
42885
42893
  const containerRef = useRef(null);
@@ -43096,12 +43104,18 @@ var init_GameCanvas3D2 = __esm({
43096
43104
  },
43097
43105
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
43098
43106
  );
43107
+ const UNIT_BASE_MODEL_SCALE = 0.5;
43108
+ const UNIT_BASE_BILLBOARD_HEIGHT = 1.2;
43109
+ const UNIT_BASE_PRIMITIVE_RADIUS = 0.3;
43099
43110
  const DefaultUnitRenderer = useCallback(
43100
43111
  ({ unit, position }) => {
43101
43112
  const isSelected = selectedUnitId === unit.id;
43102
43113
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43103
43114
  const hasAtlas = unitAtlasUrl(unit) !== null;
43104
43115
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
43116
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
43117
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
43118
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
43105
43119
  return /* @__PURE__ */ jsxs(
43106
43120
  "group",
43107
43121
  {
@@ -43119,7 +43133,8 @@ var init_GameCanvas3D2 = __esm({
43119
43133
  UnitSpriteBillboard,
43120
43134
  {
43121
43135
  sheetUrl: initialFrame.sheetUrl,
43122
- resolveFrame: () => resolveUnitFrame(unit.id)
43136
+ resolveFrame: () => resolveUnitFrame(unit.id),
43137
+ height: billboardHeight
43123
43138
  }
43124
43139
  ) })
43125
43140
  ) : unit.modelUrl ? (
@@ -43128,22 +43143,22 @@ var init_GameCanvas3D2 = __esm({
43128
43143
  ModelLoader,
43129
43144
  {
43130
43145
  url: unit.modelUrl,
43131
- scale: 0.5,
43146
+ scale: modelScale,
43132
43147
  fallbackGeometry: "box",
43133
43148
  castShadow: true
43134
43149
  }
43135
43150
  )
43136
43151
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
43137
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
43138
- /* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
43152
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius, 0], children: [
43153
+ /* @__PURE__ */ jsx("cylinderGeometry", { args: [primitiveRadius, primitiveRadius, primitiveRadius * 0.33, 8] }),
43139
43154
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
43140
43155
  ] }),
43141
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
43142
- /* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
43156
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius * 2, 0], children: [
43157
+ /* @__PURE__ */ jsx("capsuleGeometry", { args: [primitiveRadius * 0.67, primitiveRadius * 1.33, 4, 8] }),
43143
43158
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
43144
43159
  ] }),
43145
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
43146
- /* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
43160
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius * 3, 0], children: [
43161
+ /* @__PURE__ */ jsx("sphereGeometry", { args: [primitiveRadius * 0.4, 8, 8] }),
43147
43162
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
43148
43163
  ] })
43149
43164
  ] }),
@@ -43176,7 +43191,7 @@ var init_GameCanvas3D2 = __esm({
43176
43191
  }
43177
43192
  );
43178
43193
  },
43179
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
43194
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
43180
43195
  );
43181
43196
  const DefaultFeatureRenderer = useCallback(
43182
43197
  ({
@@ -43319,33 +43334,35 @@ var init_GameCanvas3D2 = __esm({
43319
43334
  fadeStrength: 1
43320
43335
  }
43321
43336
  ),
43322
- tiles.map((tile, index) => {
43323
- const position = gridToWorld(
43324
- tile.x,
43325
- tile.z ?? tile.y ?? 0,
43326
- tile.elevation ?? 0
43327
- );
43328
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
43329
- return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
43330
- }),
43331
- features.map((feature, index) => {
43332
- const position = gridToWorld(
43333
- feature.x,
43334
- feature.z ?? feature.y ?? 0,
43335
- (feature.elevation ?? 0) + 0.5
43336
- );
43337
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
43338
- return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
43339
- }),
43340
- units.map((unit) => {
43341
- const position = gridToWorld(
43342
- unit.x ?? 0,
43343
- unit.z ?? unit.y ?? 0,
43344
- (unit.elevation ?? 0) + 0.5
43345
- );
43346
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
43347
- return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
43348
- }),
43337
+ /* @__PURE__ */ jsxs("group", { scale, children: [
43338
+ tiles.map((tile, index) => {
43339
+ const position = gridToWorld(
43340
+ tile.x,
43341
+ tile.z ?? tile.y ?? 0,
43342
+ tile.elevation ?? 0
43343
+ );
43344
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
43345
+ return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
43346
+ }),
43347
+ features.map((feature, index) => {
43348
+ const position = gridToWorld(
43349
+ feature.x,
43350
+ feature.z ?? feature.y ?? 0,
43351
+ (feature.elevation ?? 0) + 0.5
43352
+ );
43353
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
43354
+ return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
43355
+ }),
43356
+ units.map((unit) => {
43357
+ const position = gridToWorld(
43358
+ unit.x ?? 0,
43359
+ unit.z ?? unit.y ?? 0,
43360
+ (unit.elevation ?? 0) + 0.5
43361
+ );
43362
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
43363
+ return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
43364
+ })
43365
+ ] }),
43349
43366
  children,
43350
43367
  /* @__PURE__ */ jsx(
43351
43368
  OrbitControls,
@@ -43388,6 +43405,8 @@ function GameBoard3D({
43388
43405
  features = [],
43389
43406
  cameraMode = "perspective",
43390
43407
  backgroundColor = "#2a1a1a",
43408
+ unitScale = 1,
43409
+ scale = 0.45,
43391
43410
  tileClickEvent,
43392
43411
  unitClickEvent,
43393
43412
  attackEvent,
@@ -43488,6 +43507,8 @@ function GameBoard3D({
43488
43507
  selectedUnitId,
43489
43508
  validMoves,
43490
43509
  attackTargets,
43510
+ unitScale,
43511
+ scale,
43491
43512
  className: "game-board-3d__canvas w-full min-h-[85vh]"
43492
43513
  }
43493
43514
  ),
@@ -45647,6 +45668,8 @@ function RoguelikeBoard({
45647
45668
  assetManifest: propAssetManifest,
45648
45669
  scale = 0.45,
45649
45670
  unitScale = 1,
45671
+ spriteHeightRatio = 1.5,
45672
+ spriteMaxWidthRatio = 0.6,
45650
45673
  moveEvent,
45651
45674
  playAgainEvent,
45652
45675
  gameEndEvent,
@@ -45794,7 +45817,9 @@ function RoguelikeBoard({
45794
45817
  scale,
45795
45818
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
45796
45819
  assetManifest: propAssetManifest,
45797
- unitScale
45820
+ unitScale,
45821
+ spriteHeightRatio,
45822
+ spriteMaxWidthRatio
45798
45823
  }
45799
45824
  ) }),
45800
45825
  !isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -50388,6 +50413,9 @@ function TowerDefenseBoard({
50388
50413
  waveActive: propWaveActive,
50389
50414
  towerCost = 25,
50390
50415
  scale = 0.45,
50416
+ unitScale = 1,
50417
+ spriteHeightRatio = 1.5,
50418
+ spriteMaxWidthRatio = 0.6,
50391
50419
  placeTowerEvent,
50392
50420
  startWaveEvent,
50393
50421
  playAgainEvent,
@@ -50495,7 +50523,10 @@ function TowerDefenseBoard({
50495
50523
  onTileClick: handleTileClick,
50496
50524
  onTileHover: (x, y) => setHoveredTile({ x, y }),
50497
50525
  onTileLeave: () => setHoveredTile(null),
50498
- scale
50526
+ scale,
50527
+ unitScale,
50528
+ spriteHeightRatio,
50529
+ spriteMaxWidthRatio
50499
50530
  }
50500
50531
  ),
50501
50532
  hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsx(Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
@@ -50831,6 +50862,8 @@ function WorldMapBoard({
50831
50862
  isLoading,
50832
50863
  scale = 0.4,
50833
50864
  unitScale = 2.5,
50865
+ spriteHeightRatio = 1.5,
50866
+ spriteMaxWidthRatio = 0.6,
50834
50867
  allowMoveAllHeroes = false,
50835
50868
  isInRange = defaultIsInRange,
50836
50869
  heroSelectEvent,
@@ -51068,6 +51101,8 @@ function WorldMapBoard({
51068
51101
  effectSpriteUrls,
51069
51102
  resolveUnitFrame,
51070
51103
  unitScale,
51104
+ spriteHeightRatio,
51105
+ spriteMaxWidthRatio,
51071
51106
  diamondTopY,
51072
51107
  enableCamera
51073
51108
  }