@almadar/ui 5.103.0 → 5.105.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/avl/index.cjs +168 -88
  2. package/dist/avl/index.css +3 -3
  3. package/dist/avl/index.js +168 -88
  4. package/dist/components/core/atoms/AtlasImage.d.ts +2 -2
  5. package/dist/components/core/atoms/FlipContainer.d.ts +1 -1
  6. package/dist/components/core/molecules/Card.d.ts +1 -1
  7. package/dist/components/core/molecules/Chart.d.ts +3 -3
  8. package/dist/components/core/molecules/DataGrid.d.ts +1 -1
  9. package/dist/components/core/molecules/DataList.d.ts +1 -1
  10. package/dist/components/core/molecules/DocPagination.d.ts +8 -1
  11. package/dist/components/core/molecules/DocSearch.d.ts +8 -1
  12. package/dist/components/core/molecules/FlipCard.d.ts +1 -1
  13. package/dist/components/core/molecules/LineChart.d.ts +3 -1
  14. package/dist/components/core/molecules/MapView.d.ts +18 -1
  15. package/dist/components/core/molecules/SortableList.d.ts +1 -1
  16. package/dist/components/core/molecules/TableView.d.ts +1 -1
  17. package/dist/components/core/organisms/DataTable.d.ts +7 -3
  18. package/dist/components/core/organisms/debug/RuntimeDebugger.d.ts +10 -1
  19. package/dist/components/core/organisms/debug/tabs/EntitiesTab.d.ts +2 -1
  20. package/dist/components/core/organisms/debug/tabs/EventDispatcherTab.d.ts +2 -1
  21. package/dist/components/core/organisms/debug/tabs/EventFlowTab.d.ts +6 -1
  22. package/dist/components/core/organisms/debug/tabs/GuardsPanel.d.ts +6 -1
  23. package/dist/components/core/organisms/debug/tabs/ServerBridgeTab.d.ts +12 -1
  24. package/dist/components/core/organisms/debug/tabs/TicksTab.d.ts +2 -1
  25. package/dist/components/core/organisms/debug/tabs/TraitsTab.d.ts +2 -1
  26. package/dist/components/core/organisms/debug/tabs/TransitionTimeline.d.ts +11 -1
  27. package/dist/components/core/organisms/debug/tabs/VerificationTab.d.ts +8 -1
  28. package/dist/components/game/2d/atoms/ActionButton.d.ts +2 -1
  29. package/dist/components/game/2d/atoms/ChoiceButton.d.ts +2 -1
  30. package/dist/components/game/2d/atoms/ComboCounter.d.ts +2 -1
  31. package/dist/components/game/2d/atoms/ControlButton.d.ts +2 -1
  32. package/dist/components/game/2d/atoms/DamageNumber.d.ts +2 -1
  33. package/dist/components/game/2d/atoms/DialogueBubble.d.ts +2 -1
  34. package/dist/components/game/2d/atoms/GameIcon.d.ts +2 -1
  35. package/dist/components/game/2d/atoms/HealthBar.d.ts +2 -1
  36. package/dist/components/game/2d/atoms/ItemSlot.d.ts +2 -1
  37. package/dist/components/game/2d/atoms/MiniMap.d.ts +2 -1
  38. package/dist/components/game/2d/atoms/ResourceCounter.d.ts +2 -1
  39. package/dist/components/game/2d/atoms/ScoreDisplay.d.ts +2 -1
  40. package/dist/components/game/2d/atoms/StatusEffect.d.ts +2 -1
  41. package/dist/components/game/2d/atoms/TimerDisplay.d.ts +2 -1
  42. package/dist/components/game/2d/atoms/TurnIndicator.d.ts +2 -1
  43. package/dist/components/game/2d/atoms/WaypointMarker.d.ts +2 -1
  44. package/dist/components/game/2d/molecules/Canvas2D.d.ts +6 -5
  45. package/dist/components/game/2d/molecules/GameHud.d.ts +2 -1
  46. package/dist/components/game/2d/molecules/GameMenu.d.ts +2 -1
  47. package/dist/components/game/2d/molecules/InventoryGrid.d.ts +2 -1
  48. package/dist/components/game/2d/molecules/ResourceBar.d.ts +2 -1
  49. package/dist/components/game/2d/molecules/SideCanvas2D.d.ts +36 -0
  50. package/dist/components/game/2d/molecules/StatBadge.d.ts +2 -1
  51. package/dist/components/game/3d/atoms/EventMarker3D.d.ts +17 -0
  52. package/dist/components/game/3d/atoms/SpriteBillboard3D.d.ts +18 -0
  53. package/dist/components/game/3d/index.cjs +539 -496
  54. package/dist/components/game/3d/index.js +367 -324
  55. package/dist/components/game/3d/molecules/FeatureMesh3D.d.ts +21 -0
  56. package/dist/components/game/3d/molecules/GameCamera3D.d.ts +35 -0
  57. package/dist/components/game/3d/molecules/Lighting3D.d.ts +10 -2
  58. package/dist/components/game/3d/molecules/SideScene3D.d.ts +31 -0
  59. package/dist/components/game/3d/molecules/TileMesh3D.d.ts +28 -0
  60. package/dist/components/game/3d/molecules/UnitMesh3D.d.ts +29 -0
  61. package/dist/components/game/shared/game3dTheme.d.ts +55 -0
  62. package/dist/components/game/shared/isometric.d.ts +38 -0
  63. package/dist/components/game/shared/isometricTypes.d.ts +4 -0
  64. package/dist/components/game/shared/lib/editorUtils.d.ts +8 -8
  65. package/dist/components/index.cjs +156 -83
  66. package/dist/components/index.css +3 -3
  67. package/dist/components/index.js +160 -87
  68. package/dist/hooks/useGitHub.d.ts +7 -7
  69. package/dist/marketing/index.cjs +2 -2
  70. package/dist/marketing/index.js +2 -2
  71. package/dist/providers/EventBusProvider.d.ts +1 -1
  72. package/dist/providers/SelectionProvider.d.ts +1 -1
  73. package/dist/providers/ServerBridge.d.ts +1 -1
  74. package/dist/providers/index.cjs +164 -84
  75. package/dist/providers/index.css +3 -3
  76. package/dist/providers/index.js +164 -84
  77. package/dist/runtime/index.cjs +164 -84
  78. package/dist/runtime/index.css +3 -3
  79. package/dist/runtime/index.js +164 -84
  80. package/package.json +10 -15
@@ -7975,7 +7975,7 @@ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric")
7975
7975
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
7976
7976
  return { x: Math.round(tileX), y: Math.round(tileY) };
7977
7977
  }
7978
- var TILE_WIDTH, TILE_HEIGHT, FLOOR_HEIGHT, DIAMOND_TOP_Y, FEATURE_COLORS;
7978
+ var TILE_WIDTH, TILE_HEIGHT, FLOOR_HEIGHT, DIAMOND_TOP_Y, FEATURE_COLORS, TERRAIN_COLORS, TEAM_COLORS, TEAM_SHADOW_COLORS, HIGHLIGHT_COLORS, SELECTION_RING_COLOR, GRID_STROKE_COLOR, BACKGROUND_FALLBACK_COLOR, MINIMAP_TERRAIN_COLORS, MINIMAP_UNIT_COLORS, UNIT_LABEL_BG_COLORS, SIDE_PLATFORM_COLORS, SIDE_PLAYER_COLOR, SIDE_PLAYER_EYE_COLOR, SIDE_SKY_GRADIENT_TOP, SIDE_SKY_GRADIENT_BOTTOM, SIDE_GRID_COLOR, SIDE_FX_COLOR, SIDE_PLATFORM_BEVEL_COLOR, SIDE_PLATFORM_SHADOW_COLOR, SIDE_HAZARD_STRIPE_COLOR, SIDE_GOAL_GLOW_COLOR, DEFAULT_BG_COLOR;
7979
7979
  var init_isometric = __esm({
7980
7980
  "components/game/shared/isometric.ts"() {
7981
7981
  TILE_WIDTH = 256;
@@ -7992,14 +7992,79 @@ var init_isometric = __esm({
7992
7992
  mountain: "#78716c",
7993
7993
  default: "#9ca3af"
7994
7994
  };
7995
+ TERRAIN_COLORS = {
7996
+ water: "#3b82f6",
7997
+ mountain: "#78716c",
7998
+ stone: "#9ca3af",
7999
+ default: "#4ade80"
8000
+ };
8001
+ TEAM_COLORS = {
8002
+ player: "#3b82f6",
8003
+ enemy: "#ef4444",
8004
+ neutral: "#6b7280",
8005
+ default: "#6b7280"
8006
+ };
8007
+ TEAM_SHADOW_COLORS = {
8008
+ player: "rgba(0,150,255,0.6)",
8009
+ default: "rgba(255,50,50,0.6)"
8010
+ };
8011
+ HIGHLIGHT_COLORS = {
8012
+ hover: "rgba(255,255,255,0.15)",
8013
+ validMove: "rgba(74,222,128,0.25)",
8014
+ attack: "rgba(239,68,68,0.35)"
8015
+ };
8016
+ SELECTION_RING_COLOR = "rgba(0,200,255,0.8)";
8017
+ GRID_STROKE_COLOR = "rgba(0,0,0,0.2)";
8018
+ BACKGROUND_FALLBACK_COLOR = "#1a1a2e";
8019
+ MINIMAP_TERRAIN_COLORS = {
8020
+ water: "#3b82f6",
8021
+ mountain: "#78716c",
8022
+ default: "#4ade80"
8023
+ };
8024
+ MINIMAP_UNIT_COLORS = {
8025
+ player: "#60a5fa",
8026
+ enemy: "#f87171",
8027
+ neutral: "#9ca3af",
8028
+ default: "#9ca3af"
8029
+ };
8030
+ UNIT_LABEL_BG_COLORS = {
8031
+ player: "rgba(59,130,246,0.9)",
8032
+ enemy: "rgba(239,68,68,0.9)",
8033
+ neutral: "rgba(107,114,128,0.9)",
8034
+ default: "rgba(107,114,128,0.9)"
8035
+ };
8036
+ SIDE_PLATFORM_COLORS = {
8037
+ ground: "#4a7c59",
8038
+ platform: "#7c6b4a",
8039
+ hazard: "#c0392b",
8040
+ goal: "#f1c40f"
8041
+ };
8042
+ SIDE_PLAYER_COLOR = "#3498db";
8043
+ SIDE_PLAYER_EYE_COLOR = "#ffffff";
8044
+ SIDE_SKY_GRADIENT_TOP = "#1a1a2e";
8045
+ SIDE_SKY_GRADIENT_BOTTOM = "#16213e";
8046
+ SIDE_GRID_COLOR = "rgba(255, 255, 255, 0.03)";
8047
+ SIDE_FX_COLOR = "#ffe066";
8048
+ SIDE_PLATFORM_BEVEL_COLOR = "rgba(255,255,255,0.15)";
8049
+ SIDE_PLATFORM_SHADOW_COLOR = "rgba(0,0,0,0.3)";
8050
+ SIDE_HAZARD_STRIPE_COLOR = "#e74c3c";
8051
+ SIDE_GOAL_GLOW_COLOR = "rgba(241, 196, 15, 0.5)";
8052
+ DEFAULT_BG_COLOR = "#5c94fc";
7995
8053
  }
7996
8054
  });
7997
8055
 
7998
8056
  // components/game/shared/spriteSheetConstants.ts
7999
- var SHEET_COLUMNS;
8057
+ var SHEET_COLUMNS, SPRITE_SHEET_LAYOUT;
8000
8058
  var init_spriteSheetConstants = __esm({
8001
8059
  "components/game/shared/spriteSheetConstants.ts"() {
8002
8060
  SHEET_COLUMNS = 8;
8061
+ SPRITE_SHEET_LAYOUT = {
8062
+ idle: { row: 0, frames: 4, frameRate: 6, loop: true },
8063
+ walk: { row: 1, frames: 8, frameRate: 10, loop: true },
8064
+ attack: { row: 2, frames: 6, frameRate: 12, loop: false },
8065
+ hit: { row: 3, frames: 3, frameRate: 8, loop: false },
8066
+ death: { row: 4, frames: 6, frameRate: 8, loop: false }
8067
+ };
8003
8068
  }
8004
8069
  });
8005
8070
 
@@ -10550,7 +10615,10 @@ var init_useUnitSpriteAtlas = __esm({
10550
10615
  init_spriteAnimation();
10551
10616
  }
10552
10617
  });
10553
- function SideView({
10618
+ function normalizeBackdrop(bg) {
10619
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10620
+ }
10621
+ function SideCanvas2D({
10554
10622
  player,
10555
10623
  platforms,
10556
10624
  worldWidth,
@@ -10559,7 +10627,7 @@ function SideView({
10559
10627
  canvasHeight,
10560
10628
  follow,
10561
10629
  bgColor,
10562
- backgroundImage,
10630
+ backgroundImage: backgroundImageRaw,
10563
10631
  playerSprite,
10564
10632
  tileSprites,
10565
10633
  effects,
@@ -10567,27 +10635,22 @@ function SideView({
10567
10635
  keyUpMap,
10568
10636
  className
10569
10637
  }) {
10638
+ const backgroundImage = normalizeBackdrop(backgroundImageRaw);
10570
10639
  const canvasRef = useRef(null);
10571
10640
  const eventBus = useEventBus();
10572
10641
  const keysRef = useRef(/* @__PURE__ */ new Set());
10573
- const imageCache2 = useRef(/* @__PURE__ */ new Map());
10574
- const [loadedImages, setLoadedImages] = useState(/* @__PURE__ */ new Set());
10575
- const loadImage = useCallback((url) => {
10576
- if (!url) return null;
10577
- const cached = imageCache2.current.get(url);
10578
- if (cached?.complete && cached.naturalWidth > 0) {
10579
- if (!loadedImages.has(url)) setLoadedImages((prev) => new Set(prev).add(url));
10580
- return cached;
10581
- }
10582
- if (!cached) {
10583
- const img = new Image();
10584
- img.crossOrigin = "anonymous";
10585
- img.src = url;
10586
- img.onload = () => setLoadedImages((prev) => new Set(prev).add(url));
10587
- imageCache2.current.set(url, img);
10642
+ const spriteUrls = useMemo(() => {
10643
+ const urls = [];
10644
+ if (backgroundImage?.url) urls.push(backgroundImage.url);
10645
+ if (playerSprite?.url) urls.push(playerSprite.url);
10646
+ if (tileSprites) {
10647
+ for (const asset of Object.values(tileSprites)) {
10648
+ if (asset?.url) urls.push(asset.url);
10649
+ }
10588
10650
  }
10589
- return null;
10590
- }, [loadedImages]);
10651
+ return urls;
10652
+ }, [backgroundImage, playerSprite, tileSprites]);
10653
+ const { getImage } = useImageCache(spriteUrls);
10591
10654
  useEffect(() => {
10592
10655
  if (typeof window === "undefined") return;
10593
10656
  const canvas = canvasRef.current;
@@ -10700,7 +10763,7 @@ function SideView({
10700
10763
  camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
10701
10764
  camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
10702
10765
  }
10703
- const bgImage = bgImg ? loadImage(bgImg.url) : null;
10766
+ const bgImage = bgImg ? getImage(bgImg.url) : void 0;
10704
10767
  const bgSrc = bgImage ? resolveAssetSource(bgImage, bgImg, NOOP) : null;
10705
10768
  if (bgSrc) {
10706
10769
  blit(ctx, bgSrc, 0, 0, cw, ch);
@@ -10711,12 +10774,12 @@ function SideView({
10711
10774
  ctx.fillRect(0, 0, cw, ch);
10712
10775
  } else {
10713
10776
  const grad = ctx.createLinearGradient(0, 0, 0, ch);
10714
- grad.addColorStop(0, SKY_GRADIENT_TOP);
10715
- grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
10777
+ grad.addColorStop(0, SIDE_SKY_GRADIENT_TOP);
10778
+ grad.addColorStop(1, SIDE_SKY_GRADIENT_BOTTOM);
10716
10779
  ctx.fillStyle = grad;
10717
10780
  ctx.fillRect(0, 0, cw, ch);
10718
10781
  }
10719
- ctx.strokeStyle = GRID_COLOR;
10782
+ ctx.strokeStyle = SIDE_GRID_COLOR;
10720
10783
  ctx.lineWidth = 1;
10721
10784
  const gridSize = 32;
10722
10785
  for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
@@ -10736,7 +10799,7 @@ function SideView({
10736
10799
  const platY = plat.y - camY;
10737
10800
  const platType = plat.type ?? "ground";
10738
10801
  const spriteAsset = tSprites?.[platType];
10739
- const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
10802
+ const tileImg = spriteAsset ? getImage(spriteAsset.url) : void 0;
10740
10803
  const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
10741
10804
  if (tileSrc) {
10742
10805
  const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
@@ -10751,15 +10814,15 @@ function SideView({
10751
10814
  ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
10752
10815
  }
10753
10816
  } else {
10754
- const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
10817
+ const color = SIDE_PLATFORM_COLORS[platType] ?? SIDE_PLATFORM_COLORS.ground;
10755
10818
  ctx.fillStyle = color;
10756
10819
  ctx.fillRect(platX, platY, plat.width, plat.height);
10757
- ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
10820
+ ctx.fillStyle = SIDE_PLATFORM_BEVEL_COLOR;
10758
10821
  ctx.fillRect(platX, platY, plat.width, 3);
10759
- ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
10822
+ ctx.fillStyle = SIDE_PLATFORM_SHADOW_COLOR;
10760
10823
  ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
10761
10824
  if (platType === "hazard") {
10762
- ctx.strokeStyle = "#e74c3c";
10825
+ ctx.strokeStyle = SIDE_HAZARD_STRIPE_COLOR;
10763
10826
  ctx.lineWidth = 2;
10764
10827
  for (let sx = platX; sx < platX + plat.width; sx += 12) {
10765
10828
  ctx.beginPath();
@@ -10769,7 +10832,7 @@ function SideView({
10769
10832
  }
10770
10833
  }
10771
10834
  if (platType === "goal") {
10772
- ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
10835
+ ctx.fillStyle = SIDE_GOAL_GLOW_COLOR;
10773
10836
  ctx.beginPath();
10774
10837
  ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
10775
10838
  ctx.fill();
@@ -10781,7 +10844,7 @@ function SideView({
10781
10844
  const ppx = px - camX;
10782
10845
  const ppy = py - camY;
10783
10846
  const facingRight = auth.facingRight ?? true;
10784
- const playerImg = pSprite ? loadImage(pSprite.url) : null;
10847
+ const playerImg = pSprite ? getImage(pSprite.url) : void 0;
10785
10848
  const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
10786
10849
  if (playerSrc) {
10787
10850
  ctx.save();
@@ -10794,7 +10857,7 @@ function SideView({
10794
10857
  }
10795
10858
  ctx.restore();
10796
10859
  } else {
10797
- ctx.fillStyle = PLAYER_COLOR;
10860
+ ctx.fillStyle = SIDE_PLAYER_COLOR;
10798
10861
  const radius = Math.min(pw, ph) * 0.25;
10799
10862
  ctx.beginPath();
10800
10863
  ctx.moveTo(ppx + radius, ppy);
@@ -10810,7 +10873,7 @@ function SideView({
10810
10873
  const eyeY = ppy + ph * 0.3;
10811
10874
  const eyeSize = 3;
10812
10875
  const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
10813
- ctx.fillStyle = PLAYER_EYE_COLOR;
10876
+ ctx.fillStyle = SIDE_PLAYER_EYE_COLOR;
10814
10877
  ctx.beginPath();
10815
10878
  ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
10816
10879
  ctx.fill();
@@ -10824,7 +10887,7 @@ function SideView({
10824
10887
  const alpha = Math.min(1, fx.ttl / 4);
10825
10888
  const prev = ctx.globalAlpha;
10826
10889
  ctx.globalAlpha = alpha;
10827
- ctx.fillStyle = "#ffe066";
10890
+ ctx.fillStyle = SIDE_FX_COLOR;
10828
10891
  ctx.beginPath();
10829
10892
  ctx.arc(fxScreenX, fxScreenY, 12, 0, Math.PI * 2);
10830
10893
  ctx.fill();
@@ -10832,7 +10895,7 @@ function SideView({
10832
10895
  }
10833
10896
  };
10834
10897
  return interp.startLoop(drawFrame);
10835
- }, [interp.startLoop, loadImage]);
10898
+ }, [interp.startLoop, getImage]);
10836
10899
  return /* @__PURE__ */ jsx(
10837
10900
  "canvas",
10838
10901
  {
@@ -10844,6 +10907,33 @@ function SideView({
10844
10907
  }
10845
10908
  );
10846
10909
  }
10910
+ var NOOP;
10911
+ var init_SideCanvas2D = __esm({
10912
+ "components/game/2d/molecules/SideCanvas2D.tsx"() {
10913
+ "use client";
10914
+ init_cn();
10915
+ init_useEventBus();
10916
+ init_useImageCache();
10917
+ init_atlasSlice();
10918
+ init_useRenderInterpolation();
10919
+ init_verificationRegistry();
10920
+ init_isometric();
10921
+ NOOP = () => {
10922
+ };
10923
+ SideCanvas2D.displayName = "SideCanvas2D";
10924
+ }
10925
+ });
10926
+ function normalizeBackdrop2(bg) {
10927
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10928
+ }
10929
+ function resolveTileFallbackColor(tile) {
10930
+ const override = tile.color;
10931
+ return override ?? TERRAIN_COLORS[tile.terrain ?? ""] ?? TERRAIN_COLORS.default;
10932
+ }
10933
+ function resolveUnitTeamColor(unit) {
10934
+ const override = unit.tint;
10935
+ return override ?? TEAM_COLORS[unit.team ?? ""] ?? TEAM_COLORS.default;
10936
+ }
10847
10937
  function Canvas2D({
10848
10938
  // Closed-circuit
10849
10939
  className,
@@ -10858,7 +10948,7 @@ function Canvas2D({
10858
10948
  effects: _effectsPropRaw = [],
10859
10949
  platforms,
10860
10950
  player,
10861
- backgroundImage,
10951
+ backgroundImage: backgroundImageRaw,
10862
10952
  // Interaction state
10863
10953
  selectedUnitId = null,
10864
10954
  validMoves = [],
@@ -10893,12 +10983,13 @@ function Canvas2D({
10893
10983
  // Side-view asset resolution
10894
10984
  playerSprite,
10895
10985
  tileSprites,
10896
- bgColor = "#5c94fc",
10986
+ bgColor = DEFAULT_BG_COLOR,
10897
10987
  worldWidth = 800,
10898
10988
  worldHeight = 400,
10899
10989
  // Remote asset loading
10900
10990
  assetManifest
10901
10991
  }) {
10992
+ const backgroundImage = normalizeBackdrop2(backgroundImageRaw);
10902
10993
  const isSide = projection === "side";
10903
10994
  const isFree = projection === "free";
10904
10995
  const flatLike = projection === "hex" || projection === "flat" || isFree;
@@ -11082,7 +11173,7 @@ function Canvas2D({
11082
11173
  return sortedTiles.map((t2) => ({
11083
11174
  x: t2.x,
11084
11175
  y: t2.y,
11085
- color: t2.terrain === "water" ? "#3b82f6" : t2.terrain === "mountain" ? "#78716c" : "#4ade80"
11176
+ color: MINIMAP_TERRAIN_COLORS[t2.terrain ?? ""] ?? MINIMAP_TERRAIN_COLORS.default
11086
11177
  }));
11087
11178
  }, [showMinimap, sortedTiles]);
11088
11179
  const miniMapUnits = useMemo(() => {
@@ -11090,7 +11181,7 @@ function Canvas2D({
11090
11181
  return units.filter((u) => u.position).map((u) => ({
11091
11182
  x: u.position.x,
11092
11183
  y: u.position.y,
11093
- color: u.team === "player" ? "#60a5fa" : u.team === "enemy" ? "#f87171" : "#9ca3af",
11184
+ color: MINIMAP_UNIT_COLORS[u.team ?? ""] ?? MINIMAP_UNIT_COLORS.default,
11094
11185
  isPlayer: u.team === "player"
11095
11186
  }));
11096
11187
  }, [showMinimap, units]);
@@ -11127,7 +11218,7 @@ function Canvas2D({
11127
11218
  }
11128
11219
  }
11129
11220
  } else {
11130
- ctx.fillStyle = "#1a1a2e";
11221
+ ctx.fillStyle = BACKGROUND_FALLBACK_COLOR;
11131
11222
  ctx.fillRect(0, 0, viewportSize.width, viewportSize.height);
11132
11223
  }
11133
11224
  if (sortedTiles.length === 0 && units.length === 0 && features.length === 0) return;
@@ -11157,15 +11248,15 @@ function Canvas2D({
11157
11248
  } else if (img && img.naturalWidth === 0) {
11158
11249
  ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
11159
11250
  } else if (squareGrid) {
11160
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
11251
+ ctx.fillStyle = resolveTileFallbackColor(tile);
11161
11252
  ctx.fillRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
11162
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
11253
+ ctx.strokeStyle = GRID_STROKE_COLOR;
11163
11254
  ctx.lineWidth = 1;
11164
11255
  ctx.strokeRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
11165
11256
  } else {
11166
11257
  const centerX = pos.x + scaledTileWidth / 2;
11167
11258
  const topY = pos.y + scaledDiamondTopY;
11168
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
11259
+ ctx.fillStyle = resolveTileFallbackColor(tile);
11169
11260
  ctx.beginPath();
11170
11261
  ctx.moveTo(centerX, topY);
11171
11262
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -11173,7 +11264,7 @@ function Canvas2D({
11173
11264
  ctx.lineTo(pos.x, topY + scaledFloorHeight / 2);
11174
11265
  ctx.closePath();
11175
11266
  ctx.fill();
11176
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
11267
+ ctx.strokeStyle = GRID_STROKE_COLOR;
11177
11268
  ctx.lineWidth = 1;
11178
11269
  ctx.stroke();
11179
11270
  }
@@ -11194,11 +11285,11 @@ function Canvas2D({
11194
11285
  ctx.fill();
11195
11286
  };
11196
11287
  if (hoveredTile && hoveredTile.x === tile.x && hoveredTile.y === tile.y) {
11197
- drawHighlight("rgba(255, 255, 255, 0.15)");
11288
+ drawHighlight(HIGHLIGHT_COLORS.hover);
11198
11289
  }
11199
11290
  const tileKey = `${tile.x},${tile.y}`;
11200
- if (validMoveSet.has(tileKey)) drawHighlight("rgba(74, 222, 128, 0.25)");
11201
- if (attackTargetSet.has(tileKey)) drawHighlight("rgba(239, 68, 68, 0.35)");
11291
+ if (validMoveSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.validMove);
11292
+ if (attackTargetSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.attack);
11202
11293
  if (debug2) {
11203
11294
  const centerX = pos.x + scaledTileWidth / 2;
11204
11295
  const centerY = squareGrid ? pos.y + scaledTileWidth / 2 : pos.y + scaledFloorHeight / 2 + scaledDiamondTopY;
@@ -11272,9 +11363,9 @@ function Canvas2D({
11272
11363
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11273
11364
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
11274
11365
  const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
11275
- const SHEET_ROWS = 5;
11276
11366
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
11277
- const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11367
+ const sheetFrameH = img ? img.naturalHeight / LEGACY_SHEET_ROWS : 0;
11368
+ const legacyFrame = frameRect(0, 0, SHEET_COLUMNS, sheetFrameW, sheetFrameH);
11278
11369
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11279
11370
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11280
11371
  const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
@@ -11292,17 +11383,16 @@ function Canvas2D({
11292
11383
  ctx.globalAlpha = 0.25;
11293
11384
  if (img) {
11294
11385
  if (unitIsSheet) {
11295
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11386
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11296
11387
  } else if (unitSrc) {
11297
11388
  blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11298
11389
  } else {
11299
11390
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11300
11391
  }
11301
11392
  } else {
11302
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
11303
11393
  ctx.beginPath();
11304
11394
  ctx.arc(ghostCenterX, ghostGroundY - 16 * scale, 20 * scale, 0, Math.PI * 2);
11305
- ctx.fillStyle = color;
11395
+ ctx.fillStyle = resolveUnitTeamColor(unit);
11306
11396
  ctx.fill();
11307
11397
  }
11308
11398
  ctx.restore();
@@ -11310,7 +11400,7 @@ function Canvas2D({
11310
11400
  if (isSelected) {
11311
11401
  ctx.beginPath();
11312
11402
  ctx.ellipse(centerX, groundY, drawW / 2 + 4 * scale, 12 * scale, 0, 0, Math.PI * 2);
11313
- ctx.strokeStyle = "rgba(0, 200, 255, 0.8)";
11403
+ ctx.strokeStyle = SELECTION_RING_COLOR;
11314
11404
  ctx.lineWidth = 3;
11315
11405
  ctx.stroke();
11316
11406
  }
@@ -11327,7 +11417,7 @@ function Canvas2D({
11327
11417
  const spriteY = groundY - fDrawH - (frame.applyBreathing ? breatheOffset : 0);
11328
11418
  ctx.save();
11329
11419
  if (unit.team) {
11330
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11420
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
11331
11421
  ctx.shadowBlur = 12 * scale;
11332
11422
  }
11333
11423
  if (frame.flipX) {
@@ -11342,7 +11432,7 @@ function Canvas2D({
11342
11432
  const spriteY = groundY - drawH - breatheOffset;
11343
11433
  const drawUnit = (x) => {
11344
11434
  if (unitIsSheet) {
11345
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11435
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, x, spriteY, drawW, drawH);
11346
11436
  } else if (unitSrc) {
11347
11437
  blit(ctx, unitSrc, x, spriteY, drawW, drawH);
11348
11438
  } else {
@@ -11351,7 +11441,7 @@ function Canvas2D({
11351
11441
  };
11352
11442
  if (unit.team) {
11353
11443
  ctx.save();
11354
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11444
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
11355
11445
  ctx.shadowBlur = 12 * scale;
11356
11446
  drawUnit(centerX - drawW / 2);
11357
11447
  ctx.restore();
@@ -11359,10 +11449,9 @@ function Canvas2D({
11359
11449
  drawUnit(centerX - drawW / 2);
11360
11450
  }
11361
11451
  } else {
11362
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
11363
11452
  ctx.beginPath();
11364
11453
  ctx.arc(centerX, groundY - 20 * scale - breatheOffset, 20 * scale, 0, Math.PI * 2);
11365
- ctx.fillStyle = color;
11454
+ ctx.fillStyle = resolveUnitTeamColor(unit);
11366
11455
  ctx.fill();
11367
11456
  ctx.strokeStyle = "rgba(255,255,255,0.8)";
11368
11457
  ctx.lineWidth = 2;
@@ -11601,7 +11690,7 @@ function Canvas2D({
11601
11690
  }
11602
11691
  if (isSide) {
11603
11692
  return /* @__PURE__ */ jsx(Box, { ref: containerRef, className: cn("relative overflow-hidden w-full h-full", className), children: /* @__PURE__ */ jsx(
11604
- SideView,
11693
+ SideCanvas2D,
11605
11694
  {
11606
11695
  player,
11607
11696
  platforms: platforms && platforms.length ? platforms : DEFAULT_PLATFORMS,
@@ -11699,7 +11788,7 @@ function Canvas2D({
11699
11788
  {
11700
11789
  as: "span",
11701
11790
  className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap block",
11702
- style: { background: unit.team === "player" ? "rgba(59,130,246,0.9)" : unit.team === "enemy" ? "rgba(239,68,68,0.9)" : "rgba(107,114,128,0.9)" },
11791
+ style: { background: UNIT_LABEL_BG_COLORS[unit.team ?? ""] ?? UNIT_LABEL_BG_COLORS.default },
11703
11792
  children: unit.name
11704
11793
  }
11705
11794
  ),
@@ -11723,7 +11812,7 @@ function Canvas2D({
11723
11812
  }
11724
11813
  );
11725
11814
  }
11726
- var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11815
+ var LEGACY_SHEET_ROWS, DEFAULT_PLATFORMS;
11727
11816
  var init_Canvas2D = __esm({
11728
11817
  "components/game/2d/molecules/Canvas2D.tsx"() {
11729
11818
  "use client";
@@ -11745,19 +11834,9 @@ var init_Canvas2D = __esm({
11745
11834
  init_verificationRegistry();
11746
11835
  init_isometric();
11747
11836
  init_spriteSheetConstants();
11748
- PLATFORM_COLORS = {
11749
- ground: "#4a7c59",
11750
- platform: "#7c6b4a",
11751
- hazard: "#c0392b",
11752
- goal: "#f1c40f"
11753
- };
11754
- NOOP = () => {
11755
- };
11756
- PLAYER_COLOR = "#3498db";
11757
- PLAYER_EYE_COLOR = "#ffffff";
11758
- SKY_GRADIENT_TOP = "#1a1a2e";
11759
- SKY_GRADIENT_BOTTOM = "#16213e";
11760
- GRID_COLOR = "rgba(255, 255, 255, 0.03)";
11837
+ init_spriteAnimation();
11838
+ init_SideCanvas2D();
11839
+ LEGACY_SHEET_ROWS = Object.keys(SPRITE_SHEET_LAYOUT).length;
11761
11840
  DEFAULT_PLATFORMS = [
11762
11841
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
11763
11842
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -17709,9 +17788,9 @@ var init_BiologyCanvas = __esm({
17709
17788
  }
17710
17789
  });
17711
17790
 
17712
- // node_modules/katex/dist/katex.min.css
17791
+ // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
17713
17792
  var init_katex_min = __esm({
17714
- "node_modules/katex/dist/katex.min.css"() {
17793
+ "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
17715
17794
  }
17716
17795
  });
17717
17796
  var Tabs;
@@ -29722,8 +29801,9 @@ var init_LineChart = __esm({
29722
29801
  const safeData = data ?? [];
29723
29802
  const sortedData = useMemo(() => {
29724
29803
  if (safeData.length === 0) return [];
29804
+ if (!safeData.some((d) => d.date != null)) return [...safeData];
29725
29805
  return [...safeData].sort(
29726
- (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
29806
+ (a, b) => new Date(a.date ?? 0).getTime() - new Date(b.date ?? 0).getTime()
29727
29807
  );
29728
29808
  }, [safeData]);
29729
29809
  const points = useMemo(() => {
@@ -30474,13 +30554,13 @@ var init_MapView = __esm({
30474
30554
  shadowSize: [41, 41]
30475
30555
  });
30476
30556
  L.Marker.prototype.options.icon = defaultIcon;
30477
- const { useEffect: useEffect67, useRef: useRef66, useCallback: useCallback98, useState: useState97 } = React96__default;
30557
+ const { useEffect: useEffect68, useRef: useRef67, useCallback: useCallback99, useState: useState97 } = React96__default;
30478
30558
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
30479
30559
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
30480
30560
  function MapUpdater({ centerLat, centerLng, zoom }) {
30481
30561
  const map = useMap();
30482
- const prevRef = useRef66({ centerLat, centerLng, zoom });
30483
- useEffect67(() => {
30562
+ const prevRef = useRef67({ centerLat, centerLng, zoom });
30563
+ useEffect68(() => {
30484
30564
  const prev = prevRef.current;
30485
30565
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
30486
30566
  map.setView([centerLat, centerLng], zoom);
@@ -30491,7 +30571,7 @@ var init_MapView = __esm({
30491
30571
  }
30492
30572
  function MapClickHandler({ onMapClick }) {
30493
30573
  const map = useMap();
30494
- useEffect67(() => {
30574
+ useEffect68(() => {
30495
30575
  if (!onMapClick) return;
30496
30576
  const handler = (e) => {
30497
30577
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -30520,7 +30600,7 @@ var init_MapView = __esm({
30520
30600
  }) {
30521
30601
  const eventBus = useEventBus2();
30522
30602
  const [clickedPosition, setClickedPosition] = useState97(null);
30523
- const handleMapClick = useCallback98((lat, lng) => {
30603
+ const handleMapClick = useCallback99((lat, lng) => {
30524
30604
  if (showClickedPin) {
30525
30605
  setClickedPosition({ lat, lng });
30526
30606
  }
@@ -30529,7 +30609,7 @@ var init_MapView = __esm({
30529
30609
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
30530
30610
  }
30531
30611
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
30532
- const handleMarkerClick = useCallback98((marker) => {
30612
+ const handleMarkerClick = useCallback99((marker) => {
30533
30613
  onMarkerClick?.(marker);
30534
30614
  if (markerClickEvent) {
30535
30615
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.103.0",
3
+ "version": "5.105.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -116,12 +116,6 @@
116
116
  "registry": "https://registry.npmjs.org",
117
117
  "access": "public"
118
118
  },
119
- "scripts": {
120
- "build": "tsup && tsc -p tsconfig.build.json",
121
- "build:watch": "tsup --watch",
122
- "typecheck": "tsc --noEmit",
123
- "lint": "eslint --no-warn-ignored --max-warnings 0 ."
124
- },
125
119
  "dependencies": {
126
120
  "@almadar/core": "^10.16.0",
127
121
  "@almadar/evaluator": ">=2.9.2",
@@ -213,7 +207,8 @@
213
207
  "tsx": "^4.7.0",
214
208
  "typescript": "^5.4.0",
215
209
  "vite": "^5.2.0",
216
- "vitest": "^3.2.6"
210
+ "vitest": "^3.2.6",
211
+ "turbo": "^2.8.17"
217
212
  },
218
213
  "repository": {
219
214
  "type": "git",
@@ -229,13 +224,13 @@
229
224
  "hooks"
230
225
  ],
231
226
  "homepage": "https://github.com/almadar-io/almadar#readme",
232
- "pnpm": {
233
- "overrides": {
234
- "@types/react": "^19.0.0",
235
- "@types/react-dom": "^19.0.0"
236
- }
237
- },
238
227
  "overrides": {
239
228
  "@almadar/core": "$@almadar/core"
229
+ },
230
+ "scripts": {
231
+ "build": "tsup && tsc -p tsconfig.build.json",
232
+ "build:watch": "tsup --watch",
233
+ "typecheck": "tsc --noEmit",
234
+ "lint": "eslint --no-warn-ignored --max-warnings 0 ."
240
235
  }
241
- }
236
+ }