@almadar/ui 5.55.0 → 5.57.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.
@@ -10,7 +10,7 @@ import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, Chevro
10
10
  import { createPortal } from 'react-dom';
11
11
  import { useTranslate, useEventBus as useEventBus$1 } from '@almadar/ui/hooks';
12
12
  import { useUISlots, UISlotProvider, useTheme } from '@almadar/ui/context';
13
- import { evaluate, createMinimalContext } from '@almadar/evaluator';
13
+ import { evaluateGuard, evaluate, createMinimalContext } from '@almadar/evaluator';
14
14
  import { Link, Outlet, useLocation } from 'react-router-dom';
15
15
  import ELK from 'elkjs/lib/elk.bundled.js';
16
16
  import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light.js';
@@ -48,7 +48,7 @@ import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoade
48
48
  import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
49
49
  import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
50
50
  import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
51
- import { StateMachineManager, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, interpolateValue, createContextFromBindings, InMemoryPersistence } from '@almadar/runtime';
51
+ import { StateMachineManager, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, createContextFromBindings, InMemoryPersistence } from '@almadar/runtime';
52
52
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
53
53
 
54
54
  var __defProp = Object.defineProperty;
@@ -10795,6 +10795,8 @@ function IsometricCanvas({
10795
10795
  showMinimap = true,
10796
10796
  enableCamera = true,
10797
10797
  unitScale = 1,
10798
+ spriteHeightRatio = 1.5,
10799
+ spriteMaxWidthRatio = 0.6,
10798
10800
  // Asset resolution
10799
10801
  getTerrainSprite,
10800
10802
  getFeatureSprite,
@@ -11185,8 +11187,8 @@ function IsometricCanvas({
11185
11187
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
11186
11188
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
11187
11189
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
11188
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
11189
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
11190
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
11191
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11190
11192
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
11191
11193
  let drawH = unitDrawH;
11192
11194
  let drawW = unitDrawH * ar;
@@ -11562,14 +11564,32 @@ var init_boardEntity = __esm({
11562
11564
  "components/game/organisms/boardEntity.ts"() {
11563
11565
  }
11564
11566
  });
11567
+ function buildDefaultBattleTiles() {
11568
+ const tiles = [];
11569
+ for (let y = 0; y < BATTLE_GRID_H; y++) {
11570
+ for (let x = 0; x < BATTLE_GRID_W; x++) {
11571
+ const variant = (x * 3 + y * 7 + (x ^ y)) % BATTLE_TERRAIN_SPRITES.length;
11572
+ tiles.push({
11573
+ x,
11574
+ y,
11575
+ terrain: ["grass", "dirt", "planks", "stone", "stone"][variant],
11576
+ terrainSprite: BATTLE_TERRAIN_SPRITES[variant],
11577
+ passable: true
11578
+ });
11579
+ }
11580
+ }
11581
+ return tiles;
11582
+ }
11565
11583
  function BattleBoard({
11566
11584
  entity,
11567
11585
  tiles: propTiles,
11568
11586
  units: propUnits,
11569
11587
  features: propFeatures,
11570
11588
  assetManifest: propAssetManifest,
11571
- scale = 0.45,
11589
+ scale = 0.25,
11572
11590
  unitScale = 1,
11591
+ spriteHeightRatio = 1.5,
11592
+ spriteMaxWidthRatio = 0.6,
11573
11593
  header,
11574
11594
  sidebar,
11575
11595
  actions,
@@ -11593,10 +11613,11 @@ function BattleBoard({
11593
11613
  className
11594
11614
  }) {
11595
11615
  const board = boardEntity(entity) ?? {};
11596
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
11616
+ const rawTiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
11617
+ const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
11597
11618
  const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
11598
- const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
11599
- const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
11619
+ const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
11620
+ const boardHeight = num(board.gridHeight ?? board.boardHeight, BATTLE_GRID_H);
11600
11621
  const assetManifest = propAssetManifest ?? board.assetManifest;
11601
11622
  const backgroundImage = board.backgroundImage;
11602
11623
  const units = rows(board.units);
@@ -11860,7 +11881,9 @@ function BattleBoard({
11860
11881
  hasActiveEffects: hasActiveEffects2,
11861
11882
  effectSpriteUrls,
11862
11883
  resolveUnitFrame,
11863
- unitScale
11884
+ unitScale,
11885
+ spriteHeightRatio,
11886
+ spriteMaxWidthRatio
11864
11887
  }
11865
11888
  ),
11866
11889
  overlay && overlay(ctx)
@@ -11916,6 +11939,7 @@ function BattleBoard({
11916
11939
  ] }) }))
11917
11940
  ] });
11918
11941
  }
11942
+ var BATTLE_CDN, BATTLE_GRID_W, BATTLE_GRID_H, BATTLE_TERRAIN_SPRITES, DEFAULT_BATTLE_TILES;
11919
11943
  var init_BattleBoard = __esm({
11920
11944
  "components/game/organisms/BattleBoard.tsx"() {
11921
11945
  "use client";
@@ -11928,6 +11952,17 @@ var init_BattleBoard = __esm({
11928
11952
  init_IsometricCanvas();
11929
11953
  init_boardEntity();
11930
11954
  init_isometric();
11955
+ BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
11956
+ BATTLE_GRID_W = 16;
11957
+ BATTLE_GRID_H = 16;
11958
+ BATTLE_TERRAIN_SPRITES = [
11959
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
11960
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
11961
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
11962
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
11963
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
11964
+ ];
11965
+ DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
11931
11966
  BattleBoard.displayName = "BattleBoard";
11932
11967
  }
11933
11968
  });
@@ -11935,7 +11970,7 @@ function BattleTemplate({
11935
11970
  entity,
11936
11971
  scale = 0.45,
11937
11972
  unitScale = 1,
11938
- tiles = DEFAULT_BATTLE_TILES,
11973
+ tiles = DEFAULT_BATTLE_TILES2,
11939
11974
  units = DEFAULT_BATTLE_UNITS,
11940
11975
  features = DEFAULT_BATTLE_FEATURES,
11941
11976
  assetManifest = DEFAULT_BATTLE_MANIFEST,
@@ -11964,12 +11999,12 @@ function BattleTemplate({
11964
11999
  }
11965
12000
  );
11966
12001
  }
11967
- var CDN, DEFAULT_BATTLE_TILES, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12002
+ var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
11968
12003
  var init_BattleTemplate = __esm({
11969
12004
  "components/game/templates/BattleTemplate.tsx"() {
11970
12005
  init_BattleBoard();
11971
12006
  CDN = "https://almadar-kflow-assets.web.app/shared";
11972
- DEFAULT_BATTLE_TILES = [
12007
+ DEFAULT_BATTLE_TILES2 = [
11973
12008
  { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11974
12009
  { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11975
12010
  { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
@@ -41831,6 +41866,7 @@ var init_GameCanvas3D2 = __esm({
41831
41866
  attackTargets = [],
41832
41867
  selectedTileIds = [],
41833
41868
  selectedUnitId = null,
41869
+ unitScale = 1,
41834
41870
  children
41835
41871
  }, ref) => {
41836
41872
  const containerRef = useRef(null);
@@ -42047,12 +42083,18 @@ var init_GameCanvas3D2 = __esm({
42047
42083
  },
42048
42084
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
42049
42085
  );
42086
+ const UNIT_BASE_MODEL_SCALE = 0.5;
42087
+ const UNIT_BASE_BILLBOARD_HEIGHT = 1.2;
42088
+ const UNIT_BASE_PRIMITIVE_RADIUS = 0.3;
42050
42089
  const DefaultUnitRenderer = useCallback(
42051
42090
  ({ unit, position }) => {
42052
42091
  const isSelected = selectedUnitId === unit.id;
42053
42092
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
42054
42093
  const hasAtlas = unitAtlasUrl(unit) !== null;
42055
42094
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
42095
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
42096
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
42097
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
42056
42098
  return /* @__PURE__ */ jsxs(
42057
42099
  "group",
42058
42100
  {
@@ -42070,7 +42112,8 @@ var init_GameCanvas3D2 = __esm({
42070
42112
  UnitSpriteBillboard,
42071
42113
  {
42072
42114
  sheetUrl: initialFrame.sheetUrl,
42073
- resolveFrame: () => resolveUnitFrame(unit.id)
42115
+ resolveFrame: () => resolveUnitFrame(unit.id),
42116
+ height: billboardHeight
42074
42117
  }
42075
42118
  ) })
42076
42119
  ) : unit.modelUrl ? (
@@ -42079,22 +42122,22 @@ var init_GameCanvas3D2 = __esm({
42079
42122
  ModelLoader,
42080
42123
  {
42081
42124
  url: unit.modelUrl,
42082
- scale: 0.5,
42125
+ scale: modelScale,
42083
42126
  fallbackGeometry: "box",
42084
42127
  castShadow: true
42085
42128
  }
42086
42129
  )
42087
42130
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
42088
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
42089
- /* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
42131
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius, 0], children: [
42132
+ /* @__PURE__ */ jsx("cylinderGeometry", { args: [primitiveRadius, primitiveRadius, primitiveRadius * 0.33, 8] }),
42090
42133
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
42091
42134
  ] }),
42092
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
42093
- /* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
42135
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius * 2, 0], children: [
42136
+ /* @__PURE__ */ jsx("capsuleGeometry", { args: [primitiveRadius * 0.67, primitiveRadius * 1.33, 4, 8] }),
42094
42137
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
42095
42138
  ] }),
42096
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
42097
- /* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
42139
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius * 3, 0], children: [
42140
+ /* @__PURE__ */ jsx("sphereGeometry", { args: [primitiveRadius * 0.4, 8, 8] }),
42098
42141
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
42099
42142
  ] })
42100
42143
  ] }),
@@ -42127,7 +42170,7 @@ var init_GameCanvas3D2 = __esm({
42127
42170
  }
42128
42171
  );
42129
42172
  },
42130
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
42173
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
42131
42174
  );
42132
42175
  const DefaultFeatureRenderer = useCallback(
42133
42176
  ({
@@ -42270,33 +42313,35 @@ var init_GameCanvas3D2 = __esm({
42270
42313
  fadeStrength: 1
42271
42314
  }
42272
42315
  ),
42273
- tiles.map((tile, index) => {
42274
- const position = gridToWorld(
42275
- tile.x,
42276
- tile.z ?? tile.y ?? 0,
42277
- tile.elevation ?? 0
42278
- );
42279
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
42280
- return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
42281
- }),
42282
- features.map((feature, index) => {
42283
- const position = gridToWorld(
42284
- feature.x,
42285
- feature.z ?? feature.y ?? 0,
42286
- (feature.elevation ?? 0) + 0.5
42287
- );
42288
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
42289
- return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
42290
- }),
42291
- units.map((unit) => {
42292
- const position = gridToWorld(
42293
- unit.x ?? 0,
42294
- unit.z ?? unit.y ?? 0,
42295
- (unit.elevation ?? 0) + 0.5
42296
- );
42297
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
42298
- return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
42299
- }),
42316
+ /* @__PURE__ */ jsxs("group", { children: [
42317
+ tiles.map((tile, index) => {
42318
+ const position = gridToWorld(
42319
+ tile.x,
42320
+ tile.z ?? tile.y ?? 0,
42321
+ tile.elevation ?? 0
42322
+ );
42323
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
42324
+ return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
42325
+ }),
42326
+ features.map((feature, index) => {
42327
+ const position = gridToWorld(
42328
+ feature.x,
42329
+ feature.z ?? feature.y ?? 0,
42330
+ (feature.elevation ?? 0) + 0.5
42331
+ );
42332
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
42333
+ return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
42334
+ }),
42335
+ units.map((unit) => {
42336
+ const position = gridToWorld(
42337
+ unit.x ?? 0,
42338
+ unit.z ?? unit.y ?? 0,
42339
+ (unit.elevation ?? 0) + 0.5
42340
+ );
42341
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
42342
+ return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
42343
+ })
42344
+ ] }),
42300
42345
  children,
42301
42346
  /* @__PURE__ */ jsx(
42302
42347
  OrbitControls,
@@ -42339,6 +42384,8 @@ function GameBoard3D({
42339
42384
  features = [],
42340
42385
  cameraMode = "perspective",
42341
42386
  backgroundColor = "#2a1a1a",
42387
+ unitScale = 1,
42388
+ scale = 0.45,
42342
42389
  tileClickEvent,
42343
42390
  unitClickEvent,
42344
42391
  attackEvent,
@@ -42439,6 +42486,8 @@ function GameBoard3D({
42439
42486
  selectedUnitId,
42440
42487
  validMoves,
42441
42488
  attackTargets,
42489
+ unitScale,
42490
+ scale,
42442
42491
  className: "game-board-3d__canvas w-full min-h-[85vh]"
42443
42492
  }
42444
42493
  ),
@@ -44407,6 +44456,35 @@ var init_PricingPageTemplate = __esm({
44407
44456
  PricingPageTemplate.displayName = "PricingPageTemplate";
44408
44457
  }
44409
44458
  });
44459
+ function dungeonTerrain(x, y, stairsX, stairsY) {
44460
+ const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
44461
+ const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
44462
+ const isWall = isBorder || isPillar;
44463
+ if (x === stairsX && y === stairsY) {
44464
+ return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
44465
+ }
44466
+ if (isWall) {
44467
+ return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
44468
+ }
44469
+ const variant = (x * 3 + y * 7) % 5;
44470
+ const sprites = [
44471
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
44472
+ `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
44473
+ `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
44474
+ `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
44475
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
44476
+ ];
44477
+ return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
44478
+ }
44479
+ function buildDefaultDungeonTiles(stairsX, stairsY) {
44480
+ const tiles = [];
44481
+ for (let y = 0; y < DUNGEON_GRID_H; y++) {
44482
+ for (let x = 0; x < DUNGEON_GRID_W; x++) {
44483
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
44484
+ }
44485
+ }
44486
+ return tiles;
44487
+ }
44410
44488
  function RoguelikeBoard({
44411
44489
  entity,
44412
44490
  tiles: propTiles,
@@ -44422,15 +44500,19 @@ function RoguelikeBoard({
44422
44500
  stairsX: propStairsX,
44423
44501
  stairsY: propStairsY,
44424
44502
  assetManifest: propAssetManifest,
44425
- scale = 0.45,
44503
+ scale = 0.25,
44426
44504
  unitScale = 1,
44505
+ spriteHeightRatio = 1.5,
44506
+ spriteMaxWidthRatio = 0.6,
44427
44507
  moveEvent,
44428
44508
  playAgainEvent,
44429
44509
  gameEndEvent,
44430
44510
  className
44431
44511
  }) {
44432
44512
  const board = boardEntity(entity) ?? {};
44433
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
44513
+ const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
44514
+ const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
44515
+ const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
44434
44516
  const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
44435
44517
  const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
44436
44518
  const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
@@ -44440,8 +44522,8 @@ function RoguelikeBoard({
44440
44522
  const depth = propDepth ?? num(board.depth, 1);
44441
44523
  const result = propResult ?? (str(board.result) || "none");
44442
44524
  const phase = propPhase ?? (str(board.phase) || "player_turn");
44443
- propStairsX ?? num(board.stairsX, 3);
44444
- propStairsY ?? num(board.stairsY, 3);
44525
+ propStairsX ?? num(board.stairsX, 14);
44526
+ propStairsY ?? num(board.stairsY, 14);
44445
44527
  const eventBus = useEventBus();
44446
44528
  const { t } = useTranslate();
44447
44529
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -44571,7 +44653,9 @@ function RoguelikeBoard({
44571
44653
  scale,
44572
44654
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
44573
44655
  assetManifest: propAssetManifest,
44574
- unitScale
44656
+ unitScale,
44657
+ spriteHeightRatio,
44658
+ spriteMaxWidthRatio
44575
44659
  }
44576
44660
  ) }),
44577
44661
  !isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -44615,7 +44699,7 @@ function RoguelikeBoard({
44615
44699
  ] }) })
44616
44700
  ] });
44617
44701
  }
44618
- var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
44702
+ var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
44619
44703
  var init_RoguelikeBoard = __esm({
44620
44704
  "components/game/organisms/RoguelikeBoard.tsx"() {
44621
44705
  "use client";
@@ -44628,39 +44712,19 @@ var init_RoguelikeBoard = __esm({
44628
44712
  init_IsometricCanvas();
44629
44713
  init_boardEntity();
44630
44714
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
44631
- DEFAULT_TILES2 = [
44632
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44633
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44634
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44635
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44636
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44637
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44638
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44639
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44640
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44641
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44642
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44643
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44644
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44645
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44646
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44647
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44648
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44649
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44650
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
44651
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44652
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44653
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44654
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44655
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44656
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
44657
- ];
44715
+ DUNGEON_GRID_W = 16;
44716
+ DUNGEON_GRID_H = 16;
44717
+ buildDefaultDungeonTiles(14, 14);
44658
44718
  DEFAULT_ENEMIES = [
44659
- { id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
44660
- { id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
44719
+ { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
44720
+ { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
44721
+ { id: "e3", x: 3, y: 10, hp: 6, attack: 2 },
44722
+ { id: "e4", x: 12, y: 8, hp: 5, attack: 3 }
44661
44723
  ];
44662
44724
  DEFAULT_ITEMS = [
44663
- { id: "i1", x: 2, y: 2, kind: "health_potion" }
44725
+ { id: "i1", x: 3, y: 3, kind: "health_potion" },
44726
+ { id: "i2", x: 7, y: 9, kind: "sword" },
44727
+ { id: "i3", x: 11, y: 5, kind: "shield" }
44664
44728
  ];
44665
44729
  FEATURE_SPRITE = {
44666
44730
  health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
@@ -48887,6 +48951,22 @@ var init_ToastSlot = __esm({
48887
48951
  ToastSlot.displayName = "ToastSlot";
48888
48952
  }
48889
48953
  });
48954
+ function buildDefaultTDTiles() {
48955
+ const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
48956
+ const tiles = [];
48957
+ for (let y = 0; y < TD_GRID_H; y++) {
48958
+ for (let x = 0; x < TD_GRID_W; x++) {
48959
+ if (pathSet.has(`${x},${y}`)) {
48960
+ tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
48961
+ } else {
48962
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
48963
+ const terrainKey = ["ground", "grass", "dirt"][variant];
48964
+ tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
48965
+ }
48966
+ }
48967
+ }
48968
+ return tiles;
48969
+ }
48890
48970
  function tilesToIso(tiles) {
48891
48971
  return tiles.map((t) => ({
48892
48972
  x: t.x,
@@ -48942,7 +49022,10 @@ function TowerDefenseBoard({
48942
49022
  result: propResult,
48943
49023
  waveActive: propWaveActive,
48944
49024
  towerCost = 25,
48945
- scale = 0.45,
49025
+ scale = 0.25,
49026
+ unitScale = 1,
49027
+ spriteHeightRatio = 1.5,
49028
+ spriteMaxWidthRatio = 0.6,
48946
49029
  placeTowerEvent,
48947
49030
  startWaveEvent,
48948
49031
  playAgainEvent,
@@ -48952,8 +49035,10 @@ function TowerDefenseBoard({
48952
49035
  const board = boardEntity(entity) ?? {};
48953
49036
  const eventBus = useEventBus();
48954
49037
  const { t } = useTranslate();
48955
- const tiles = propTiles ?? rows(board.tiles);
48956
- const path = propPath ?? rows(board.path);
49038
+ const rawTiles = propTiles ?? rows(board.tiles);
49039
+ const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
49040
+ const rawPath = propPath ?? rows(board.path);
49041
+ const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
48957
49042
  const towers = propTowers ?? rows(board.towers);
48958
49043
  const creeps = propCreeps ?? rows(board.creeps);
48959
49044
  const gold = propGold ?? num(board.gold, 100);
@@ -49050,7 +49135,10 @@ function TowerDefenseBoard({
49050
49135
  onTileClick: handleTileClick,
49051
49136
  onTileHover: (x, y) => setHoveredTile({ x, y }),
49052
49137
  onTileLeave: () => setHoveredTile(null),
49053
- scale
49138
+ scale,
49139
+ unitScale,
49140
+ spriteHeightRatio,
49141
+ spriteMaxWidthRatio
49054
49142
  }
49055
49143
  ),
49056
49144
  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)` }) })
@@ -49080,7 +49168,7 @@ function TowerDefenseBoard({
49080
49168
  ] }) })
49081
49169
  ] });
49082
49170
  }
49083
- var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
49171
+ var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE;
49084
49172
  var init_TowerDefenseBoard = __esm({
49085
49173
  "components/game/organisms/TowerDefenseBoard.tsx"() {
49086
49174
  "use client";
@@ -49093,11 +49181,67 @@ var init_TowerDefenseBoard = __esm({
49093
49181
  init_IsometricCanvas();
49094
49182
  init_boardEntity();
49095
49183
  CDN6 = "https://almadar-kflow-assets.web.app/shared/";
49184
+ TD_GRID_W = 16;
49185
+ TD_GRID_H = 16;
49096
49186
  TERRAIN_SPRITES = {
49097
49187
  ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
49098
49188
  path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
49099
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
49100
- };
49189
+ wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
49190
+ grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
49191
+ dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
49192
+ };
49193
+ DEFAULT_TD_PATH = [
49194
+ { x: 2, y: 0 },
49195
+ { x: 2, y: 1 },
49196
+ { x: 2, y: 2 },
49197
+ { x: 2, y: 3 },
49198
+ { x: 3, y: 3 },
49199
+ { x: 4, y: 3 },
49200
+ { x: 5, y: 3 },
49201
+ { x: 6, y: 3 },
49202
+ { x: 7, y: 3 },
49203
+ { x: 8, y: 3 },
49204
+ { x: 9, y: 3 },
49205
+ { x: 10, y: 3 },
49206
+ { x: 11, y: 3 },
49207
+ { x: 12, y: 3 },
49208
+ { x: 13, y: 3 },
49209
+ { x: 13, y: 4 },
49210
+ { x: 13, y: 5 },
49211
+ { x: 13, y: 6 },
49212
+ { x: 13, y: 7 },
49213
+ { x: 12, y: 7 },
49214
+ { x: 11, y: 7 },
49215
+ { x: 10, y: 7 },
49216
+ { x: 9, y: 7 },
49217
+ { x: 8, y: 7 },
49218
+ { x: 7, y: 7 },
49219
+ { x: 6, y: 7 },
49220
+ { x: 5, y: 7 },
49221
+ { x: 4, y: 7 },
49222
+ { x: 3, y: 7 },
49223
+ { x: 2, y: 7 },
49224
+ { x: 2, y: 8 },
49225
+ { x: 2, y: 9 },
49226
+ { x: 2, y: 10 },
49227
+ { x: 2, y: 11 },
49228
+ { x: 3, y: 11 },
49229
+ { x: 4, y: 11 },
49230
+ { x: 5, y: 11 },
49231
+ { x: 6, y: 11 },
49232
+ { x: 7, y: 11 },
49233
+ { x: 8, y: 11 },
49234
+ { x: 9, y: 11 },
49235
+ { x: 10, y: 11 },
49236
+ { x: 11, y: 11 },
49237
+ { x: 12, y: 11 },
49238
+ { x: 13, y: 11 },
49239
+ { x: 13, y: 12 },
49240
+ { x: 13, y: 13 },
49241
+ { x: 13, y: 14 },
49242
+ { x: 13, y: 15 }
49243
+ ];
49244
+ DEFAULT_TD_TILES = buildDefaultTDTiles();
49101
49245
  TOWER_SPRITE = `${CDN6}units/guardian.png`;
49102
49246
  CREEP_SPRITE = `${CDN6}units/scrapper.png`;
49103
49247
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
@@ -49374,6 +49518,17 @@ function heroPosition(h) {
49374
49518
  function heroMovement(h) {
49375
49519
  return num(h.movement);
49376
49520
  }
49521
+ function buildDefaultWorldTiles() {
49522
+ const tiles = [];
49523
+ for (let y = 0; y < WORLD_GRID_H; y++) {
49524
+ for (let x = 0; x < WORLD_GRID_W; x++) {
49525
+ const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
49526
+ const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
49527
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
49528
+ }
49529
+ }
49530
+ return tiles;
49531
+ }
49377
49532
  function defaultIsInRange(from, to, range) {
49378
49533
  return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
49379
49534
  }
@@ -49384,8 +49539,10 @@ function WorldMapBoard({
49384
49539
  features: propFeatures,
49385
49540
  assetManifest: propAssetManifest,
49386
49541
  isLoading,
49387
- scale = 0.4,
49542
+ scale = 0.25,
49388
49543
  unitScale = 2.5,
49544
+ spriteHeightRatio = 1.5,
49545
+ spriteMaxWidthRatio = 0.6,
49389
49546
  allowMoveAllHeroes = false,
49390
49547
  isInRange = defaultIsInRange,
49391
49548
  heroSelectEvent,
@@ -49426,7 +49583,8 @@ function WorldMapBoard({
49426
49583
  })),
49427
49584
  [entityTiles]
49428
49585
  );
49429
- const tiles = propTiles ?? derivedTiles;
49586
+ const rawTiles = propTiles ?? (derivedTiles.length > 0 ? derivedTiles : null);
49587
+ const tiles = rawTiles != null && rawTiles.length >= WORLD_GRID_W * WORLD_GRID_H ? rawTiles : DEFAULT_WORLD_TILES;
49430
49588
  const baseUnits = useMemo(
49431
49589
  () => propUnits ?? entityUnits.map((u) => ({
49432
49590
  id: str(u.id),
@@ -49623,6 +49781,8 @@ function WorldMapBoard({
49623
49781
  effectSpriteUrls,
49624
49782
  resolveUnitFrame,
49625
49783
  unitScale,
49784
+ spriteHeightRatio,
49785
+ spriteMaxWidthRatio,
49626
49786
  diamondTopY,
49627
49787
  enableCamera
49628
49788
  }
@@ -49634,6 +49794,7 @@ function WorldMapBoard({
49634
49794
  footer && footer(ctx)
49635
49795
  ] });
49636
49796
  }
49797
+ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TILES;
49637
49798
  var init_WorldMapBoard = __esm({
49638
49799
  "components/game/organisms/WorldMapBoard.tsx"() {
49639
49800
  "use client";
@@ -49644,6 +49805,17 @@ var init_WorldMapBoard = __esm({
49644
49805
  init_IsometricCanvas();
49645
49806
  init_boardEntity();
49646
49807
  init_isometric();
49808
+ WORLD_CDN = "https://almadar-kflow-assets.web.app/shared";
49809
+ WORLD_GRID_W = 16;
49810
+ WORLD_GRID_H = 16;
49811
+ WORLD_TERRAIN_DEFS = [
49812
+ { terrain: "grass", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirt_E.png`, passable: true },
49813
+ { terrain: "dirt", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, passable: true },
49814
+ { terrain: "forest", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/planks_E.png`, passable: true },
49815
+ { terrain: "stone", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, passable: false },
49816
+ { terrain: "castle", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, passable: true }
49817
+ ];
49818
+ DEFAULT_WORLD_TILES = buildDefaultWorldTiles();
49647
49819
  WorldMapBoard.displayName = "WorldMapBoard";
49648
49820
  }
49649
49821
  });
@@ -51864,7 +52036,10 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
51864
52036
  if (binding.config) {
51865
52037
  guardCtx.config = binding.config;
51866
52038
  }
51867
- const passed = interpolateValue(tick.guard, createContextFromBindings(guardCtx));
52039
+ const passed = evaluateGuard(
52040
+ tick.guard,
52041
+ createContextFromBindings(guardCtx)
52042
+ );
51868
52043
  if (!passed) {
51869
52044
  tickLog.debug("guard-blocked", { traitName, tick: tick.name, state: currentState });
51870
52045
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.55.0",
3
+ "version": "5.57.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [