@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
@@ -8020,7 +8020,7 @@ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric")
8020
8020
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
8021
8021
  return { x: Math.round(tileX), y: Math.round(tileY) };
8022
8022
  }
8023
- var TILE_WIDTH, TILE_HEIGHT, FLOOR_HEIGHT, DIAMOND_TOP_Y, FEATURE_COLORS;
8023
+ 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;
8024
8024
  var init_isometric = __esm({
8025
8025
  "components/game/shared/isometric.ts"() {
8026
8026
  TILE_WIDTH = 256;
@@ -8037,14 +8037,79 @@ var init_isometric = __esm({
8037
8037
  mountain: "#78716c",
8038
8038
  default: "#9ca3af"
8039
8039
  };
8040
+ TERRAIN_COLORS = {
8041
+ water: "#3b82f6",
8042
+ mountain: "#78716c",
8043
+ stone: "#9ca3af",
8044
+ default: "#4ade80"
8045
+ };
8046
+ TEAM_COLORS = {
8047
+ player: "#3b82f6",
8048
+ enemy: "#ef4444",
8049
+ neutral: "#6b7280",
8050
+ default: "#6b7280"
8051
+ };
8052
+ TEAM_SHADOW_COLORS = {
8053
+ player: "rgba(0,150,255,0.6)",
8054
+ default: "rgba(255,50,50,0.6)"
8055
+ };
8056
+ HIGHLIGHT_COLORS = {
8057
+ hover: "rgba(255,255,255,0.15)",
8058
+ validMove: "rgba(74,222,128,0.25)",
8059
+ attack: "rgba(239,68,68,0.35)"
8060
+ };
8061
+ SELECTION_RING_COLOR = "rgba(0,200,255,0.8)";
8062
+ GRID_STROKE_COLOR = "rgba(0,0,0,0.2)";
8063
+ BACKGROUND_FALLBACK_COLOR = "#1a1a2e";
8064
+ MINIMAP_TERRAIN_COLORS = {
8065
+ water: "#3b82f6",
8066
+ mountain: "#78716c",
8067
+ default: "#4ade80"
8068
+ };
8069
+ MINIMAP_UNIT_COLORS = {
8070
+ player: "#60a5fa",
8071
+ enemy: "#f87171",
8072
+ neutral: "#9ca3af",
8073
+ default: "#9ca3af"
8074
+ };
8075
+ UNIT_LABEL_BG_COLORS = {
8076
+ player: "rgba(59,130,246,0.9)",
8077
+ enemy: "rgba(239,68,68,0.9)",
8078
+ neutral: "rgba(107,114,128,0.9)",
8079
+ default: "rgba(107,114,128,0.9)"
8080
+ };
8081
+ SIDE_PLATFORM_COLORS = {
8082
+ ground: "#4a7c59",
8083
+ platform: "#7c6b4a",
8084
+ hazard: "#c0392b",
8085
+ goal: "#f1c40f"
8086
+ };
8087
+ SIDE_PLAYER_COLOR = "#3498db";
8088
+ SIDE_PLAYER_EYE_COLOR = "#ffffff";
8089
+ SIDE_SKY_GRADIENT_TOP = "#1a1a2e";
8090
+ SIDE_SKY_GRADIENT_BOTTOM = "#16213e";
8091
+ SIDE_GRID_COLOR = "rgba(255, 255, 255, 0.03)";
8092
+ SIDE_FX_COLOR = "#ffe066";
8093
+ SIDE_PLATFORM_BEVEL_COLOR = "rgba(255,255,255,0.15)";
8094
+ SIDE_PLATFORM_SHADOW_COLOR = "rgba(0,0,0,0.3)";
8095
+ SIDE_HAZARD_STRIPE_COLOR = "#e74c3c";
8096
+ SIDE_GOAL_GLOW_COLOR = "rgba(241, 196, 15, 0.5)";
8097
+ DEFAULT_BG_COLOR = "#5c94fc";
8040
8098
  }
8041
8099
  });
8042
8100
 
8043
8101
  // components/game/shared/spriteSheetConstants.ts
8044
- var SHEET_COLUMNS;
8102
+ var SHEET_COLUMNS, SPRITE_SHEET_LAYOUT;
8045
8103
  var init_spriteSheetConstants = __esm({
8046
8104
  "components/game/shared/spriteSheetConstants.ts"() {
8047
8105
  SHEET_COLUMNS = 8;
8106
+ SPRITE_SHEET_LAYOUT = {
8107
+ idle: { row: 0, frames: 4, frameRate: 6, loop: true },
8108
+ walk: { row: 1, frames: 8, frameRate: 10, loop: true },
8109
+ attack: { row: 2, frames: 6, frameRate: 12, loop: false },
8110
+ hit: { row: 3, frames: 3, frameRate: 8, loop: false },
8111
+ death: { row: 4, frames: 6, frameRate: 8, loop: false }
8112
+ };
8048
8113
  }
8049
8114
  });
8050
8115
 
@@ -10595,7 +10660,10 @@ var init_useUnitSpriteAtlas = __esm({
10595
10660
  init_spriteAnimation();
10596
10661
  }
10597
10662
  });
10598
- function SideView({
10663
+ function normalizeBackdrop(bg) {
10664
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10665
+ }
10666
+ function SideCanvas2D({
10599
10667
  player,
10600
10668
  platforms,
10601
10669
  worldWidth,
@@ -10604,7 +10672,7 @@ function SideView({
10604
10672
  canvasHeight,
10605
10673
  follow,
10606
10674
  bgColor,
10607
- backgroundImage,
10675
+ backgroundImage: backgroundImageRaw,
10608
10676
  playerSprite,
10609
10677
  tileSprites,
10610
10678
  effects,
@@ -10612,27 +10680,22 @@ function SideView({
10612
10680
  keyUpMap,
10613
10681
  className
10614
10682
  }) {
10683
+ const backgroundImage = normalizeBackdrop(backgroundImageRaw);
10615
10684
  const canvasRef = React96.useRef(null);
10616
10685
  const eventBus = useEventBus();
10617
10686
  const keysRef = React96.useRef(/* @__PURE__ */ new Set());
10618
- const imageCache2 = React96.useRef(/* @__PURE__ */ new Map());
10619
- const [loadedImages, setLoadedImages] = React96.useState(/* @__PURE__ */ new Set());
10620
- const loadImage = React96.useCallback((url) => {
10621
- if (!url) return null;
10622
- const cached = imageCache2.current.get(url);
10623
- if (cached?.complete && cached.naturalWidth > 0) {
10624
- if (!loadedImages.has(url)) setLoadedImages((prev) => new Set(prev).add(url));
10625
- return cached;
10626
- }
10627
- if (!cached) {
10628
- const img = new Image();
10629
- img.crossOrigin = "anonymous";
10630
- img.src = url;
10631
- img.onload = () => setLoadedImages((prev) => new Set(prev).add(url));
10632
- imageCache2.current.set(url, img);
10687
+ const spriteUrls = React96.useMemo(() => {
10688
+ const urls = [];
10689
+ if (backgroundImage?.url) urls.push(backgroundImage.url);
10690
+ if (playerSprite?.url) urls.push(playerSprite.url);
10691
+ if (tileSprites) {
10692
+ for (const asset of Object.values(tileSprites)) {
10693
+ if (asset?.url) urls.push(asset.url);
10694
+ }
10633
10695
  }
10634
- return null;
10635
- }, [loadedImages]);
10696
+ return urls;
10697
+ }, [backgroundImage, playerSprite, tileSprites]);
10698
+ const { getImage } = useImageCache(spriteUrls);
10636
10699
  React96.useEffect(() => {
10637
10700
  if (typeof window === "undefined") return;
10638
10701
  const canvas = canvasRef.current;
@@ -10745,7 +10808,7 @@ function SideView({
10745
10808
  camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
10746
10809
  camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
10747
10810
  }
10748
- const bgImage = bgImg ? loadImage(bgImg.url) : null;
10811
+ const bgImage = bgImg ? getImage(bgImg.url) : void 0;
10749
10812
  const bgSrc = bgImage ? resolveAssetSource(bgImage, bgImg, NOOP) : null;
10750
10813
  if (bgSrc) {
10751
10814
  blit(ctx, bgSrc, 0, 0, cw, ch);
@@ -10756,12 +10819,12 @@ function SideView({
10756
10819
  ctx.fillRect(0, 0, cw, ch);
10757
10820
  } else {
10758
10821
  const grad = ctx.createLinearGradient(0, 0, 0, ch);
10759
- grad.addColorStop(0, SKY_GRADIENT_TOP);
10760
- grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
10822
+ grad.addColorStop(0, SIDE_SKY_GRADIENT_TOP);
10823
+ grad.addColorStop(1, SIDE_SKY_GRADIENT_BOTTOM);
10761
10824
  ctx.fillStyle = grad;
10762
10825
  ctx.fillRect(0, 0, cw, ch);
10763
10826
  }
10764
- ctx.strokeStyle = GRID_COLOR;
10827
+ ctx.strokeStyle = SIDE_GRID_COLOR;
10765
10828
  ctx.lineWidth = 1;
10766
10829
  const gridSize = 32;
10767
10830
  for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
@@ -10781,7 +10844,7 @@ function SideView({
10781
10844
  const platY = plat.y - camY;
10782
10845
  const platType = plat.type ?? "ground";
10783
10846
  const spriteAsset = tSprites?.[platType];
10784
- const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
10847
+ const tileImg = spriteAsset ? getImage(spriteAsset.url) : void 0;
10785
10848
  const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
10786
10849
  if (tileSrc) {
10787
10850
  const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
@@ -10796,15 +10859,15 @@ function SideView({
10796
10859
  ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
10797
10860
  }
10798
10861
  } else {
10799
- const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
10862
+ const color = SIDE_PLATFORM_COLORS[platType] ?? SIDE_PLATFORM_COLORS.ground;
10800
10863
  ctx.fillStyle = color;
10801
10864
  ctx.fillRect(platX, platY, plat.width, plat.height);
10802
- ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
10865
+ ctx.fillStyle = SIDE_PLATFORM_BEVEL_COLOR;
10803
10866
  ctx.fillRect(platX, platY, plat.width, 3);
10804
- ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
10867
+ ctx.fillStyle = SIDE_PLATFORM_SHADOW_COLOR;
10805
10868
  ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
10806
10869
  if (platType === "hazard") {
10807
- ctx.strokeStyle = "#e74c3c";
10870
+ ctx.strokeStyle = SIDE_HAZARD_STRIPE_COLOR;
10808
10871
  ctx.lineWidth = 2;
10809
10872
  for (let sx = platX; sx < platX + plat.width; sx += 12) {
10810
10873
  ctx.beginPath();
@@ -10814,7 +10877,7 @@ function SideView({
10814
10877
  }
10815
10878
  }
10816
10879
  if (platType === "goal") {
10817
- ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
10880
+ ctx.fillStyle = SIDE_GOAL_GLOW_COLOR;
10818
10881
  ctx.beginPath();
10819
10882
  ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
10820
10883
  ctx.fill();
@@ -10826,7 +10889,7 @@ function SideView({
10826
10889
  const ppx = px - camX;
10827
10890
  const ppy = py - camY;
10828
10891
  const facingRight = auth.facingRight ?? true;
10829
- const playerImg = pSprite ? loadImage(pSprite.url) : null;
10892
+ const playerImg = pSprite ? getImage(pSprite.url) : void 0;
10830
10893
  const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
10831
10894
  if (playerSrc) {
10832
10895
  ctx.save();
@@ -10839,7 +10902,7 @@ function SideView({
10839
10902
  }
10840
10903
  ctx.restore();
10841
10904
  } else {
10842
- ctx.fillStyle = PLAYER_COLOR;
10905
+ ctx.fillStyle = SIDE_PLAYER_COLOR;
10843
10906
  const radius = Math.min(pw, ph) * 0.25;
10844
10907
  ctx.beginPath();
10845
10908
  ctx.moveTo(ppx + radius, ppy);
@@ -10855,7 +10918,7 @@ function SideView({
10855
10918
  const eyeY = ppy + ph * 0.3;
10856
10919
  const eyeSize = 3;
10857
10920
  const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
10858
- ctx.fillStyle = PLAYER_EYE_COLOR;
10921
+ ctx.fillStyle = SIDE_PLAYER_EYE_COLOR;
10859
10922
  ctx.beginPath();
10860
10923
  ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
10861
10924
  ctx.fill();
@@ -10869,7 +10932,7 @@ function SideView({
10869
10932
  const alpha = Math.min(1, fx.ttl / 4);
10870
10933
  const prev = ctx.globalAlpha;
10871
10934
  ctx.globalAlpha = alpha;
10872
- ctx.fillStyle = "#ffe066";
10935
+ ctx.fillStyle = SIDE_FX_COLOR;
10873
10936
  ctx.beginPath();
10874
10937
  ctx.arc(fxScreenX, fxScreenY, 12, 0, Math.PI * 2);
10875
10938
  ctx.fill();
@@ -10877,7 +10940,7 @@ function SideView({
10877
10940
  }
10878
10941
  };
10879
10942
  return interp.startLoop(drawFrame);
10880
- }, [interp.startLoop, loadImage]);
10943
+ }, [interp.startLoop, getImage]);
10881
10944
  return /* @__PURE__ */ jsxRuntime.jsx(
10882
10945
  "canvas",
10883
10946
  {
@@ -10889,6 +10952,33 @@ function SideView({
10889
10952
  }
10890
10953
  );
10891
10954
  }
10955
+ var NOOP;
10956
+ var init_SideCanvas2D = __esm({
10957
+ "components/game/2d/molecules/SideCanvas2D.tsx"() {
10958
+ "use client";
10959
+ init_cn();
10960
+ init_useEventBus();
10961
+ init_useImageCache();
10962
+ init_atlasSlice();
10963
+ init_useRenderInterpolation();
10964
+ init_verificationRegistry();
10965
+ init_isometric();
10966
+ NOOP = () => {
10967
+ };
10968
+ SideCanvas2D.displayName = "SideCanvas2D";
10969
+ }
10970
+ });
10971
+ function normalizeBackdrop2(bg) {
10972
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10973
+ }
10974
+ function resolveTileFallbackColor(tile) {
10975
+ const override = tile.color;
10976
+ return override ?? TERRAIN_COLORS[tile.terrain ?? ""] ?? TERRAIN_COLORS.default;
10977
+ }
10978
+ function resolveUnitTeamColor(unit) {
10979
+ const override = unit.tint;
10980
+ return override ?? TEAM_COLORS[unit.team ?? ""] ?? TEAM_COLORS.default;
10981
+ }
10892
10982
  function Canvas2D({
10893
10983
  // Closed-circuit
10894
10984
  className,
@@ -10903,7 +10993,7 @@ function Canvas2D({
10903
10993
  effects: _effectsPropRaw = [],
10904
10994
  platforms,
10905
10995
  player,
10906
- backgroundImage,
10996
+ backgroundImage: backgroundImageRaw,
10907
10997
  // Interaction state
10908
10998
  selectedUnitId = null,
10909
10999
  validMoves = [],
@@ -10938,12 +11028,13 @@ function Canvas2D({
10938
11028
  // Side-view asset resolution
10939
11029
  playerSprite,
10940
11030
  tileSprites,
10941
- bgColor = "#5c94fc",
11031
+ bgColor = DEFAULT_BG_COLOR,
10942
11032
  worldWidth = 800,
10943
11033
  worldHeight = 400,
10944
11034
  // Remote asset loading
10945
11035
  assetManifest
10946
11036
  }) {
11037
+ const backgroundImage = normalizeBackdrop2(backgroundImageRaw);
10947
11038
  const isSide = projection === "side";
10948
11039
  const isFree = projection === "free";
10949
11040
  const flatLike = projection === "hex" || projection === "flat" || isFree;
@@ -11127,7 +11218,7 @@ function Canvas2D({
11127
11218
  return sortedTiles.map((t2) => ({
11128
11219
  x: t2.x,
11129
11220
  y: t2.y,
11130
- color: t2.terrain === "water" ? "#3b82f6" : t2.terrain === "mountain" ? "#78716c" : "#4ade80"
11221
+ color: MINIMAP_TERRAIN_COLORS[t2.terrain ?? ""] ?? MINIMAP_TERRAIN_COLORS.default
11131
11222
  }));
11132
11223
  }, [showMinimap, sortedTiles]);
11133
11224
  const miniMapUnits = React96.useMemo(() => {
@@ -11135,7 +11226,7 @@ function Canvas2D({
11135
11226
  return units.filter((u) => u.position).map((u) => ({
11136
11227
  x: u.position.x,
11137
11228
  y: u.position.y,
11138
- color: u.team === "player" ? "#60a5fa" : u.team === "enemy" ? "#f87171" : "#9ca3af",
11229
+ color: MINIMAP_UNIT_COLORS[u.team ?? ""] ?? MINIMAP_UNIT_COLORS.default,
11139
11230
  isPlayer: u.team === "player"
11140
11231
  }));
11141
11232
  }, [showMinimap, units]);
@@ -11172,7 +11263,7 @@ function Canvas2D({
11172
11263
  }
11173
11264
  }
11174
11265
  } else {
11175
- ctx.fillStyle = "#1a1a2e";
11266
+ ctx.fillStyle = BACKGROUND_FALLBACK_COLOR;
11176
11267
  ctx.fillRect(0, 0, viewportSize.width, viewportSize.height);
11177
11268
  }
11178
11269
  if (sortedTiles.length === 0 && units.length === 0 && features.length === 0) return;
@@ -11202,15 +11293,15 @@ function Canvas2D({
11202
11293
  } else if (img && img.naturalWidth === 0) {
11203
11294
  ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
11204
11295
  } else if (squareGrid) {
11205
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
11296
+ ctx.fillStyle = resolveTileFallbackColor(tile);
11206
11297
  ctx.fillRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
11207
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
11298
+ ctx.strokeStyle = GRID_STROKE_COLOR;
11208
11299
  ctx.lineWidth = 1;
11209
11300
  ctx.strokeRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
11210
11301
  } else {
11211
11302
  const centerX = pos.x + scaledTileWidth / 2;
11212
11303
  const topY = pos.y + scaledDiamondTopY;
11213
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
11304
+ ctx.fillStyle = resolveTileFallbackColor(tile);
11214
11305
  ctx.beginPath();
11215
11306
  ctx.moveTo(centerX, topY);
11216
11307
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -11218,7 +11309,7 @@ function Canvas2D({
11218
11309
  ctx.lineTo(pos.x, topY + scaledFloorHeight / 2);
11219
11310
  ctx.closePath();
11220
11311
  ctx.fill();
11221
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
11312
+ ctx.strokeStyle = GRID_STROKE_COLOR;
11222
11313
  ctx.lineWidth = 1;
11223
11314
  ctx.stroke();
11224
11315
  }
@@ -11239,11 +11330,11 @@ function Canvas2D({
11239
11330
  ctx.fill();
11240
11331
  };
11241
11332
  if (hoveredTile && hoveredTile.x === tile.x && hoveredTile.y === tile.y) {
11242
- drawHighlight("rgba(255, 255, 255, 0.15)");
11333
+ drawHighlight(HIGHLIGHT_COLORS.hover);
11243
11334
  }
11244
11335
  const tileKey = `${tile.x},${tile.y}`;
11245
- if (validMoveSet.has(tileKey)) drawHighlight("rgba(74, 222, 128, 0.25)");
11246
- if (attackTargetSet.has(tileKey)) drawHighlight("rgba(239, 68, 68, 0.35)");
11336
+ if (validMoveSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.validMove);
11337
+ if (attackTargetSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.attack);
11247
11338
  if (debug2) {
11248
11339
  const centerX = pos.x + scaledTileWidth / 2;
11249
11340
  const centerY = squareGrid ? pos.y + scaledTileWidth / 2 : pos.y + scaledFloorHeight / 2 + scaledDiamondTopY;
@@ -11317,9 +11408,9 @@ function Canvas2D({
11317
11408
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11318
11409
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
11319
11410
  const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
11320
- const SHEET_ROWS = 5;
11321
11411
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
11322
- const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11412
+ const sheetFrameH = img ? img.naturalHeight / LEGACY_SHEET_ROWS : 0;
11413
+ const legacyFrame = frameRect(0, 0, SHEET_COLUMNS, sheetFrameW, sheetFrameH);
11323
11414
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11324
11415
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11325
11416
  const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
@@ -11337,17 +11428,16 @@ function Canvas2D({
11337
11428
  ctx.globalAlpha = 0.25;
11338
11429
  if (img) {
11339
11430
  if (unitIsSheet) {
11340
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11431
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11341
11432
  } else if (unitSrc) {
11342
11433
  blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11343
11434
  } else {
11344
11435
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11345
11436
  }
11346
11437
  } else {
11347
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
11348
11438
  ctx.beginPath();
11349
11439
  ctx.arc(ghostCenterX, ghostGroundY - 16 * scale, 20 * scale, 0, Math.PI * 2);
11350
- ctx.fillStyle = color;
11440
+ ctx.fillStyle = resolveUnitTeamColor(unit);
11351
11441
  ctx.fill();
11352
11442
  }
11353
11443
  ctx.restore();
@@ -11355,7 +11445,7 @@ function Canvas2D({
11355
11445
  if (isSelected) {
11356
11446
  ctx.beginPath();
11357
11447
  ctx.ellipse(centerX, groundY, drawW / 2 + 4 * scale, 12 * scale, 0, 0, Math.PI * 2);
11358
- ctx.strokeStyle = "rgba(0, 200, 255, 0.8)";
11448
+ ctx.strokeStyle = SELECTION_RING_COLOR;
11359
11449
  ctx.lineWidth = 3;
11360
11450
  ctx.stroke();
11361
11451
  }
@@ -11372,7 +11462,7 @@ function Canvas2D({
11372
11462
  const spriteY = groundY - fDrawH - (frame.applyBreathing ? breatheOffset : 0);
11373
11463
  ctx.save();
11374
11464
  if (unit.team) {
11375
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11465
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
11376
11466
  ctx.shadowBlur = 12 * scale;
11377
11467
  }
11378
11468
  if (frame.flipX) {
@@ -11387,7 +11477,7 @@ function Canvas2D({
11387
11477
  const spriteY = groundY - drawH - breatheOffset;
11388
11478
  const drawUnit = (x) => {
11389
11479
  if (unitIsSheet) {
11390
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11480
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, x, spriteY, drawW, drawH);
11391
11481
  } else if (unitSrc) {
11392
11482
  blit(ctx, unitSrc, x, spriteY, drawW, drawH);
11393
11483
  } else {
@@ -11396,7 +11486,7 @@ function Canvas2D({
11396
11486
  };
11397
11487
  if (unit.team) {
11398
11488
  ctx.save();
11399
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11489
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
11400
11490
  ctx.shadowBlur = 12 * scale;
11401
11491
  drawUnit(centerX - drawW / 2);
11402
11492
  ctx.restore();
@@ -11404,10 +11494,9 @@ function Canvas2D({
11404
11494
  drawUnit(centerX - drawW / 2);
11405
11495
  }
11406
11496
  } else {
11407
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
11408
11497
  ctx.beginPath();
11409
11498
  ctx.arc(centerX, groundY - 20 * scale - breatheOffset, 20 * scale, 0, Math.PI * 2);
11410
- ctx.fillStyle = color;
11499
+ ctx.fillStyle = resolveUnitTeamColor(unit);
11411
11500
  ctx.fill();
11412
11501
  ctx.strokeStyle = "rgba(255,255,255,0.8)";
11413
11502
  ctx.lineWidth = 2;
@@ -11646,7 +11735,7 @@ function Canvas2D({
11646
11735
  }
11647
11736
  if (isSide) {
11648
11737
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { ref: containerRef, className: cn("relative overflow-hidden w-full h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
11649
- SideView,
11738
+ SideCanvas2D,
11650
11739
  {
11651
11740
  player,
11652
11741
  platforms: platforms && platforms.length ? platforms : DEFAULT_PLATFORMS,
@@ -11744,7 +11833,7 @@ function Canvas2D({
11744
11833
  {
11745
11834
  as: "span",
11746
11835
  className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap block",
11747
- 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)" },
11836
+ style: { background: UNIT_LABEL_BG_COLORS[unit.team ?? ""] ?? UNIT_LABEL_BG_COLORS.default },
11748
11837
  children: unit.name
11749
11838
  }
11750
11839
  ),
@@ -11768,7 +11857,7 @@ function Canvas2D({
11768
11857
  }
11769
11858
  );
11770
11859
  }
11771
- var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11860
+ var LEGACY_SHEET_ROWS, DEFAULT_PLATFORMS;
11772
11861
  var init_Canvas2D = __esm({
11773
11862
  "components/game/2d/molecules/Canvas2D.tsx"() {
11774
11863
  "use client";
@@ -11790,19 +11879,9 @@ var init_Canvas2D = __esm({
11790
11879
  init_verificationRegistry();
11791
11880
  init_isometric();
11792
11881
  init_spriteSheetConstants();
11793
- PLATFORM_COLORS = {
11794
- ground: "#4a7c59",
11795
- platform: "#7c6b4a",
11796
- hazard: "#c0392b",
11797
- goal: "#f1c40f"
11798
- };
11799
- NOOP = () => {
11800
- };
11801
- PLAYER_COLOR = "#3498db";
11802
- PLAYER_EYE_COLOR = "#ffffff";
11803
- SKY_GRADIENT_TOP = "#1a1a2e";
11804
- SKY_GRADIENT_BOTTOM = "#16213e";
11805
- GRID_COLOR = "rgba(255, 255, 255, 0.03)";
11882
+ init_spriteAnimation();
11883
+ init_SideCanvas2D();
11884
+ LEGACY_SHEET_ROWS = Object.keys(SPRITE_SHEET_LAYOUT).length;
11806
11885
  DEFAULT_PLATFORMS = [
11807
11886
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
11808
11887
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -17754,9 +17833,9 @@ var init_BiologyCanvas = __esm({
17754
17833
  }
17755
17834
  });
17756
17835
 
17757
- // node_modules/katex/dist/katex.min.css
17836
+ // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
17758
17837
  var init_katex_min = __esm({
17759
- "node_modules/katex/dist/katex.min.css"() {
17838
+ "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
17760
17839
  }
17761
17840
  });
17762
17841
  var Tabs;
@@ -29767,8 +29846,9 @@ var init_LineChart = __esm({
29767
29846
  const safeData = data ?? [];
29768
29847
  const sortedData = React96.useMemo(() => {
29769
29848
  if (safeData.length === 0) return [];
29849
+ if (!safeData.some((d) => d.date != null)) return [...safeData];
29770
29850
  return [...safeData].sort(
29771
- (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
29851
+ (a, b) => new Date(a.date ?? 0).getTime() - new Date(b.date ?? 0).getTime()
29772
29852
  );
29773
29853
  }, [safeData]);
29774
29854
  const points = React96.useMemo(() => {
@@ -30519,13 +30599,13 @@ var init_MapView = __esm({
30519
30599
  shadowSize: [41, 41]
30520
30600
  });
30521
30601
  L.Marker.prototype.options.icon = defaultIcon;
30522
- const { useEffect: useEffect67, useRef: useRef66, useCallback: useCallback98, useState: useState97 } = React96__namespace.default;
30602
+ const { useEffect: useEffect68, useRef: useRef67, useCallback: useCallback99, useState: useState97 } = React96__namespace.default;
30523
30603
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
30524
30604
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
30525
30605
  function MapUpdater({ centerLat, centerLng, zoom }) {
30526
30606
  const map = useMap();
30527
- const prevRef = useRef66({ centerLat, centerLng, zoom });
30528
- useEffect67(() => {
30607
+ const prevRef = useRef67({ centerLat, centerLng, zoom });
30608
+ useEffect68(() => {
30529
30609
  const prev = prevRef.current;
30530
30610
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
30531
30611
  map.setView([centerLat, centerLng], zoom);
@@ -30536,7 +30616,7 @@ var init_MapView = __esm({
30536
30616
  }
30537
30617
  function MapClickHandler({ onMapClick }) {
30538
30618
  const map = useMap();
30539
- useEffect67(() => {
30619
+ useEffect68(() => {
30540
30620
  if (!onMapClick) return;
30541
30621
  const handler = (e) => {
30542
30622
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -30565,7 +30645,7 @@ var init_MapView = __esm({
30565
30645
  }) {
30566
30646
  const eventBus = useEventBus2();
30567
30647
  const [clickedPosition, setClickedPosition] = useState97(null);
30568
- const handleMapClick = useCallback98((lat, lng) => {
30648
+ const handleMapClick = useCallback99((lat, lng) => {
30569
30649
  if (showClickedPin) {
30570
30650
  setClickedPosition({ lat, lng });
30571
30651
  }
@@ -30574,7 +30654,7 @@ var init_MapView = __esm({
30574
30654
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
30575
30655
  }
30576
30656
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
30577
- const handleMarkerClick = useCallback98((marker) => {
30657
+ const handleMarkerClick = useCallback99((marker) => {
30578
30658
  onMarkerClick?.(marker);
30579
30659
  if (markerClickEvent) {
30580
30660
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -1,4 +1,4 @@
1
- /* node_modules/katex/dist/katex.min.css */
1
+ /* node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css */
2
2
  @font-face {
3
3
  font-display: block;
4
4
  font-family: KaTeX_AMS;
@@ -214,11 +214,11 @@
214
214
  border-color: currentColor;
215
215
  }
216
216
  .katex .katex-version:after {
217
- content: "0.16.45";
217
+ content: "0.16.47";
218
218
  }
219
219
  .katex .katex-mathml {
220
- clip: rect(1px, 1px, 1px, 1px);
221
220
  border: 0;
221
+ clip-path: inset(50%);
222
222
  height: 1px;
223
223
  overflow: hidden;
224
224
  padding: 0;