@almadar/ui 5.54.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.
@@ -7186,6 +7186,9 @@ var init_Skeleton = __esm({
7186
7186
  Skeleton.displayName = "Skeleton";
7187
7187
  }
7188
7188
  });
7189
+ function isKnownPattern(type) {
7190
+ return type in componentMapping;
7191
+ }
7189
7192
  function getKnownPatterns() {
7190
7193
  return Object.keys(componentMapping);
7191
7194
  }
@@ -7281,6 +7284,7 @@ var init_slot_definitions = __esm({
7281
7284
  // renderer/index.ts
7282
7285
  var init_renderer = __esm({
7283
7286
  "renderer/index.ts"() {
7287
+ init_pattern_resolver();
7284
7288
  init_slot_definitions();
7285
7289
  }
7286
7290
  });
@@ -9770,6 +9774,8 @@ function IsometricCanvas({
9770
9774
  showMinimap = true,
9771
9775
  enableCamera = true,
9772
9776
  unitScale = 1,
9777
+ spriteHeightRatio = 1.5,
9778
+ spriteMaxWidthRatio = 0.6,
9773
9779
  // Asset resolution
9774
9780
  getTerrainSprite,
9775
9781
  getFeatureSprite,
@@ -10161,8 +10167,8 @@ function IsometricCanvas({
10161
10167
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
10162
10168
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
10163
10169
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
10164
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
10165
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
10170
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
10171
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10166
10172
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
10167
10173
  let drawH = unitDrawH;
10168
10174
  let drawW = unitDrawH * ar;
@@ -10546,6 +10552,8 @@ function BattleBoard({
10546
10552
  assetManifest: propAssetManifest,
10547
10553
  scale = 0.45,
10548
10554
  unitScale = 1,
10555
+ spriteHeightRatio = 1.5,
10556
+ spriteMaxWidthRatio = 0.6,
10549
10557
  header,
10550
10558
  sidebar,
10551
10559
  actions,
@@ -10836,7 +10844,9 @@ function BattleBoard({
10836
10844
  hasActiveEffects: hasActiveEffects2,
10837
10845
  effectSpriteUrls,
10838
10846
  resolveUnitFrame,
10839
- unitScale
10847
+ unitScale,
10848
+ spriteHeightRatio,
10849
+ spriteMaxWidthRatio
10840
10850
  }
10841
10851
  ),
10842
10852
  overlay && overlay(ctx)
@@ -42922,6 +42932,8 @@ var init_GameCanvas3D2 = __esm({
42922
42932
  attackTargets = [],
42923
42933
  selectedTileIds = [],
42924
42934
  selectedUnitId = null,
42935
+ unitScale = 1,
42936
+ scale = 0.45,
42925
42937
  children
42926
42938
  }, ref) => {
42927
42939
  const containerRef = React76.useRef(null);
@@ -43138,12 +43150,18 @@ var init_GameCanvas3D2 = __esm({
43138
43150
  },
43139
43151
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
43140
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;
43141
43156
  const DefaultUnitRenderer = React76.useCallback(
43142
43157
  ({ unit, position }) => {
43143
43158
  const isSelected = selectedUnitId === unit.id;
43144
43159
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43145
43160
  const hasAtlas = unitAtlasUrl(unit) !== null;
43146
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;
43147
43165
  return /* @__PURE__ */ jsxRuntime.jsxs(
43148
43166
  "group",
43149
43167
  {
@@ -43161,7 +43179,8 @@ var init_GameCanvas3D2 = __esm({
43161
43179
  UnitSpriteBillboard,
43162
43180
  {
43163
43181
  sheetUrl: initialFrame.sheetUrl,
43164
- resolveFrame: () => resolveUnitFrame(unit.id)
43182
+ resolveFrame: () => resolveUnitFrame(unit.id),
43183
+ height: billboardHeight
43165
43184
  }
43166
43185
  ) })
43167
43186
  ) : unit.modelUrl ? (
@@ -43170,22 +43189,22 @@ var init_GameCanvas3D2 = __esm({
43170
43189
  ModelLoader,
43171
43190
  {
43172
43191
  url: unit.modelUrl,
43173
- scale: 0.5,
43192
+ scale: modelScale,
43174
43193
  fallbackGeometry: "box",
43175
43194
  castShadow: true
43176
43195
  }
43177
43196
  )
43178
43197
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
43179
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
43180
- /* @__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] }),
43181
43200
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43182
43201
  ] }),
43183
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
43184
- /* @__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] }),
43185
43204
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43186
43205
  ] }),
43187
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
43188
- /* @__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] }),
43189
43208
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
43190
43209
  ] })
43191
43210
  ] }),
@@ -43218,7 +43237,7 @@ var init_GameCanvas3D2 = __esm({
43218
43237
  }
43219
43238
  );
43220
43239
  },
43221
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
43240
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
43222
43241
  );
43223
43242
  const DefaultFeatureRenderer = React76.useCallback(
43224
43243
  ({
@@ -43361,33 +43380,35 @@ var init_GameCanvas3D2 = __esm({
43361
43380
  fadeStrength: 1
43362
43381
  }
43363
43382
  ),
43364
- tiles.map((tile, index) => {
43365
- const position = gridToWorld(
43366
- tile.x,
43367
- tile.z ?? tile.y ?? 0,
43368
- tile.elevation ?? 0
43369
- );
43370
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
43371
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
43372
- }),
43373
- features.map((feature, index) => {
43374
- const position = gridToWorld(
43375
- feature.x,
43376
- feature.z ?? feature.y ?? 0,
43377
- (feature.elevation ?? 0) + 0.5
43378
- );
43379
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
43380
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
43381
- }),
43382
- units.map((unit) => {
43383
- const position = gridToWorld(
43384
- unit.x ?? 0,
43385
- unit.z ?? unit.y ?? 0,
43386
- (unit.elevation ?? 0) + 0.5
43387
- );
43388
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
43389
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
43390
- }),
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
+ ] }),
43391
43412
  children,
43392
43413
  /* @__PURE__ */ jsxRuntime.jsx(
43393
43414
  drei.OrbitControls,
@@ -43430,6 +43451,8 @@ function GameBoard3D({
43430
43451
  features = [],
43431
43452
  cameraMode = "perspective",
43432
43453
  backgroundColor = "#2a1a1a",
43454
+ unitScale = 1,
43455
+ scale = 0.45,
43433
43456
  tileClickEvent,
43434
43457
  unitClickEvent,
43435
43458
  attackEvent,
@@ -43530,6 +43553,8 @@ function GameBoard3D({
43530
43553
  selectedUnitId,
43531
43554
  validMoves,
43532
43555
  attackTargets,
43556
+ unitScale,
43557
+ scale,
43533
43558
  className: "game-board-3d__canvas w-full min-h-[85vh]"
43534
43559
  }
43535
43560
  ),
@@ -45689,6 +45714,8 @@ function RoguelikeBoard({
45689
45714
  assetManifest: propAssetManifest,
45690
45715
  scale = 0.45,
45691
45716
  unitScale = 1,
45717
+ spriteHeightRatio = 1.5,
45718
+ spriteMaxWidthRatio = 0.6,
45692
45719
  moveEvent,
45693
45720
  playAgainEvent,
45694
45721
  gameEndEvent,
@@ -45836,7 +45863,9 @@ function RoguelikeBoard({
45836
45863
  scale,
45837
45864
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
45838
45865
  assetManifest: propAssetManifest,
45839
- unitScale
45866
+ unitScale,
45867
+ spriteHeightRatio,
45868
+ spriteMaxWidthRatio
45840
45869
  }
45841
45870
  ) }),
45842
45871
  !isGameOver && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -50430,6 +50459,9 @@ function TowerDefenseBoard({
50430
50459
  waveActive: propWaveActive,
50431
50460
  towerCost = 25,
50432
50461
  scale = 0.45,
50462
+ unitScale = 1,
50463
+ spriteHeightRatio = 1.5,
50464
+ spriteMaxWidthRatio = 0.6,
50433
50465
  placeTowerEvent,
50434
50466
  startWaveEvent,
50435
50467
  playAgainEvent,
@@ -50537,7 +50569,10 @@ function TowerDefenseBoard({
50537
50569
  onTileClick: handleTileClick,
50538
50570
  onTileHover: (x, y) => setHoveredTile({ x, y }),
50539
50571
  onTileLeave: () => setHoveredTile(null),
50540
- scale
50572
+ scale,
50573
+ unitScale,
50574
+ spriteHeightRatio,
50575
+ spriteMaxWidthRatio
50541
50576
  }
50542
50577
  ),
50543
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)` }) })
@@ -50873,6 +50908,8 @@ function WorldMapBoard({
50873
50908
  isLoading,
50874
50909
  scale = 0.4,
50875
50910
  unitScale = 2.5,
50911
+ spriteHeightRatio = 1.5,
50912
+ spriteMaxWidthRatio = 0.6,
50876
50913
  allowMoveAllHeroes = false,
50877
50914
  isInRange = defaultIsInRange,
50878
50915
  heroSelectEvent,
@@ -51110,6 +51147,8 @@ function WorldMapBoard({
51110
51147
  effectSpriteUrls,
51111
51148
  resolveUnitFrame,
51112
51149
  unitScale,
51150
+ spriteHeightRatio,
51151
+ spriteMaxWidthRatio,
51113
51152
  diamondTopY,
51114
51153
  enableCamera
51115
51154
  }
@@ -52512,7 +52551,7 @@ function isPatternConfig(value) {
52512
52551
  if (value instanceof Date) return false;
52513
52552
  if (typeof value === "function") return false;
52514
52553
  const record = value;
52515
- return "type" in record && typeof record.type === "string";
52554
+ return "type" in record && typeof record.type === "string" && isKnownPattern(record.type);
52516
52555
  }
52517
52556
  function isPlainConfigObject(value) {
52518
52557
  if (React76__namespace.default.isValidElement(value)) return false;
@@ -7140,6 +7140,9 @@ var init_Skeleton = __esm({
7140
7140
  Skeleton.displayName = "Skeleton";
7141
7141
  }
7142
7142
  });
7143
+ function isKnownPattern(type) {
7144
+ return type in componentMapping;
7145
+ }
7143
7146
  function getKnownPatterns() {
7144
7147
  return Object.keys(componentMapping);
7145
7148
  }
@@ -7235,6 +7238,7 @@ var init_slot_definitions = __esm({
7235
7238
  // renderer/index.ts
7236
7239
  var init_renderer = __esm({
7237
7240
  "renderer/index.ts"() {
7241
+ init_pattern_resolver();
7238
7242
  init_slot_definitions();
7239
7243
  }
7240
7244
  });
@@ -9724,6 +9728,8 @@ function IsometricCanvas({
9724
9728
  showMinimap = true,
9725
9729
  enableCamera = true,
9726
9730
  unitScale = 1,
9731
+ spriteHeightRatio = 1.5,
9732
+ spriteMaxWidthRatio = 0.6,
9727
9733
  // Asset resolution
9728
9734
  getTerrainSprite,
9729
9735
  getFeatureSprite,
@@ -10115,8 +10121,8 @@ function IsometricCanvas({
10115
10121
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
10116
10122
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
10117
10123
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
10118
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
10119
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
10124
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
10125
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10120
10126
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
10121
10127
  let drawH = unitDrawH;
10122
10128
  let drawW = unitDrawH * ar;
@@ -10500,6 +10506,8 @@ function BattleBoard({
10500
10506
  assetManifest: propAssetManifest,
10501
10507
  scale = 0.45,
10502
10508
  unitScale = 1,
10509
+ spriteHeightRatio = 1.5,
10510
+ spriteMaxWidthRatio = 0.6,
10503
10511
  header,
10504
10512
  sidebar,
10505
10513
  actions,
@@ -10790,7 +10798,9 @@ function BattleBoard({
10790
10798
  hasActiveEffects: hasActiveEffects2,
10791
10799
  effectSpriteUrls,
10792
10800
  resolveUnitFrame,
10793
- unitScale
10801
+ unitScale,
10802
+ spriteHeightRatio,
10803
+ spriteMaxWidthRatio
10794
10804
  }
10795
10805
  ),
10796
10806
  overlay && overlay(ctx)
@@ -42876,6 +42886,8 @@ var init_GameCanvas3D2 = __esm({
42876
42886
  attackTargets = [],
42877
42887
  selectedTileIds = [],
42878
42888
  selectedUnitId = null,
42889
+ unitScale = 1,
42890
+ scale = 0.45,
42879
42891
  children
42880
42892
  }, ref) => {
42881
42893
  const containerRef = useRef(null);
@@ -43092,12 +43104,18 @@ var init_GameCanvas3D2 = __esm({
43092
43104
  },
43093
43105
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
43094
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;
43095
43110
  const DefaultUnitRenderer = useCallback(
43096
43111
  ({ unit, position }) => {
43097
43112
  const isSelected = selectedUnitId === unit.id;
43098
43113
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43099
43114
  const hasAtlas = unitAtlasUrl(unit) !== null;
43100
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;
43101
43119
  return /* @__PURE__ */ jsxs(
43102
43120
  "group",
43103
43121
  {
@@ -43115,7 +43133,8 @@ var init_GameCanvas3D2 = __esm({
43115
43133
  UnitSpriteBillboard,
43116
43134
  {
43117
43135
  sheetUrl: initialFrame.sheetUrl,
43118
- resolveFrame: () => resolveUnitFrame(unit.id)
43136
+ resolveFrame: () => resolveUnitFrame(unit.id),
43137
+ height: billboardHeight
43119
43138
  }
43120
43139
  ) })
43121
43140
  ) : unit.modelUrl ? (
@@ -43124,22 +43143,22 @@ var init_GameCanvas3D2 = __esm({
43124
43143
  ModelLoader,
43125
43144
  {
43126
43145
  url: unit.modelUrl,
43127
- scale: 0.5,
43146
+ scale: modelScale,
43128
43147
  fallbackGeometry: "box",
43129
43148
  castShadow: true
43130
43149
  }
43131
43150
  )
43132
43151
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
43133
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
43134
- /* @__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] }),
43135
43154
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
43136
43155
  ] }),
43137
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
43138
- /* @__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] }),
43139
43158
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
43140
43159
  ] }),
43141
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
43142
- /* @__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] }),
43143
43162
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
43144
43163
  ] })
43145
43164
  ] }),
@@ -43172,7 +43191,7 @@ var init_GameCanvas3D2 = __esm({
43172
43191
  }
43173
43192
  );
43174
43193
  },
43175
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
43194
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
43176
43195
  );
43177
43196
  const DefaultFeatureRenderer = useCallback(
43178
43197
  ({
@@ -43315,33 +43334,35 @@ var init_GameCanvas3D2 = __esm({
43315
43334
  fadeStrength: 1
43316
43335
  }
43317
43336
  ),
43318
- tiles.map((tile, index) => {
43319
- const position = gridToWorld(
43320
- tile.x,
43321
- tile.z ?? tile.y ?? 0,
43322
- tile.elevation ?? 0
43323
- );
43324
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
43325
- return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
43326
- }),
43327
- features.map((feature, index) => {
43328
- const position = gridToWorld(
43329
- feature.x,
43330
- feature.z ?? feature.y ?? 0,
43331
- (feature.elevation ?? 0) + 0.5
43332
- );
43333
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
43334
- return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
43335
- }),
43336
- units.map((unit) => {
43337
- const position = gridToWorld(
43338
- unit.x ?? 0,
43339
- unit.z ?? unit.y ?? 0,
43340
- (unit.elevation ?? 0) + 0.5
43341
- );
43342
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
43343
- return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
43344
- }),
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
+ ] }),
43345
43366
  children,
43346
43367
  /* @__PURE__ */ jsx(
43347
43368
  OrbitControls,
@@ -43384,6 +43405,8 @@ function GameBoard3D({
43384
43405
  features = [],
43385
43406
  cameraMode = "perspective",
43386
43407
  backgroundColor = "#2a1a1a",
43408
+ unitScale = 1,
43409
+ scale = 0.45,
43387
43410
  tileClickEvent,
43388
43411
  unitClickEvent,
43389
43412
  attackEvent,
@@ -43484,6 +43507,8 @@ function GameBoard3D({
43484
43507
  selectedUnitId,
43485
43508
  validMoves,
43486
43509
  attackTargets,
43510
+ unitScale,
43511
+ scale,
43487
43512
  className: "game-board-3d__canvas w-full min-h-[85vh]"
43488
43513
  }
43489
43514
  ),
@@ -45643,6 +45668,8 @@ function RoguelikeBoard({
45643
45668
  assetManifest: propAssetManifest,
45644
45669
  scale = 0.45,
45645
45670
  unitScale = 1,
45671
+ spriteHeightRatio = 1.5,
45672
+ spriteMaxWidthRatio = 0.6,
45646
45673
  moveEvent,
45647
45674
  playAgainEvent,
45648
45675
  gameEndEvent,
@@ -45790,7 +45817,9 @@ function RoguelikeBoard({
45790
45817
  scale,
45791
45818
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
45792
45819
  assetManifest: propAssetManifest,
45793
- unitScale
45820
+ unitScale,
45821
+ spriteHeightRatio,
45822
+ spriteMaxWidthRatio
45794
45823
  }
45795
45824
  ) }),
45796
45825
  !isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -50384,6 +50413,9 @@ function TowerDefenseBoard({
50384
50413
  waveActive: propWaveActive,
50385
50414
  towerCost = 25,
50386
50415
  scale = 0.45,
50416
+ unitScale = 1,
50417
+ spriteHeightRatio = 1.5,
50418
+ spriteMaxWidthRatio = 0.6,
50387
50419
  placeTowerEvent,
50388
50420
  startWaveEvent,
50389
50421
  playAgainEvent,
@@ -50491,7 +50523,10 @@ function TowerDefenseBoard({
50491
50523
  onTileClick: handleTileClick,
50492
50524
  onTileHover: (x, y) => setHoveredTile({ x, y }),
50493
50525
  onTileLeave: () => setHoveredTile(null),
50494
- scale
50526
+ scale,
50527
+ unitScale,
50528
+ spriteHeightRatio,
50529
+ spriteMaxWidthRatio
50495
50530
  }
50496
50531
  ),
50497
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)` }) })
@@ -50827,6 +50862,8 @@ function WorldMapBoard({
50827
50862
  isLoading,
50828
50863
  scale = 0.4,
50829
50864
  unitScale = 2.5,
50865
+ spriteHeightRatio = 1.5,
50866
+ spriteMaxWidthRatio = 0.6,
50830
50867
  allowMoveAllHeroes = false,
50831
50868
  isInRange = defaultIsInRange,
50832
50869
  heroSelectEvent,
@@ -51064,6 +51101,8 @@ function WorldMapBoard({
51064
51101
  effectSpriteUrls,
51065
51102
  resolveUnitFrame,
51066
51103
  unitScale,
51104
+ spriteHeightRatio,
51105
+ spriteMaxWidthRatio,
51067
51106
  diamondTopY,
51068
51107
  enableCamera
51069
51108
  }
@@ -52466,7 +52505,7 @@ function isPatternConfig(value) {
52466
52505
  if (value instanceof Date) return false;
52467
52506
  if (typeof value === "function") return false;
52468
52507
  const record = value;
52469
- return "type" in record && typeof record.type === "string";
52508
+ return "type" in record && typeof record.type === "string" && isKnownPattern(record.type);
52470
52509
  }
52471
52510
  function isPlainConfigObject(value) {
52472
52511
  if (React76__default.isValidElement(value)) return false;