@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
@@ -7449,7 +7449,7 @@ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric")
7449
7449
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
7450
7450
  return { x: Math.round(tileX), y: Math.round(tileY) };
7451
7451
  }
7452
- var TILE_WIDTH, TILE_HEIGHT, FLOOR_HEIGHT, DIAMOND_TOP_Y, FEATURE_COLORS;
7452
+ 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;
7453
7453
  var init_isometric = __esm({
7454
7454
  "components/game/shared/isometric.ts"() {
7455
7455
  TILE_WIDTH = 256;
@@ -7466,14 +7466,79 @@ var init_isometric = __esm({
7466
7466
  mountain: "#78716c",
7467
7467
  default: "#9ca3af"
7468
7468
  };
7469
+ TERRAIN_COLORS = {
7470
+ water: "#3b82f6",
7471
+ mountain: "#78716c",
7472
+ stone: "#9ca3af",
7473
+ default: "#4ade80"
7474
+ };
7475
+ TEAM_COLORS = {
7476
+ player: "#3b82f6",
7477
+ enemy: "#ef4444",
7478
+ neutral: "#6b7280",
7479
+ default: "#6b7280"
7480
+ };
7481
+ TEAM_SHADOW_COLORS = {
7482
+ player: "rgba(0,150,255,0.6)",
7483
+ default: "rgba(255,50,50,0.6)"
7484
+ };
7485
+ HIGHLIGHT_COLORS = {
7486
+ hover: "rgba(255,255,255,0.15)",
7487
+ validMove: "rgba(74,222,128,0.25)",
7488
+ attack: "rgba(239,68,68,0.35)"
7489
+ };
7490
+ SELECTION_RING_COLOR = "rgba(0,200,255,0.8)";
7491
+ GRID_STROKE_COLOR = "rgba(0,0,0,0.2)";
7492
+ BACKGROUND_FALLBACK_COLOR = "#1a1a2e";
7493
+ MINIMAP_TERRAIN_COLORS = {
7494
+ water: "#3b82f6",
7495
+ mountain: "#78716c",
7496
+ default: "#4ade80"
7497
+ };
7498
+ MINIMAP_UNIT_COLORS = {
7499
+ player: "#60a5fa",
7500
+ enemy: "#f87171",
7501
+ neutral: "#9ca3af",
7502
+ default: "#9ca3af"
7503
+ };
7504
+ UNIT_LABEL_BG_COLORS = {
7505
+ player: "rgba(59,130,246,0.9)",
7506
+ enemy: "rgba(239,68,68,0.9)",
7507
+ neutral: "rgba(107,114,128,0.9)",
7508
+ default: "rgba(107,114,128,0.9)"
7509
+ };
7510
+ SIDE_PLATFORM_COLORS = {
7511
+ ground: "#4a7c59",
7512
+ platform: "#7c6b4a",
7513
+ hazard: "#c0392b",
7514
+ goal: "#f1c40f"
7515
+ };
7516
+ SIDE_PLAYER_COLOR = "#3498db";
7517
+ SIDE_PLAYER_EYE_COLOR = "#ffffff";
7518
+ SIDE_SKY_GRADIENT_TOP = "#1a1a2e";
7519
+ SIDE_SKY_GRADIENT_BOTTOM = "#16213e";
7520
+ SIDE_GRID_COLOR = "rgba(255, 255, 255, 0.03)";
7521
+ SIDE_FX_COLOR = "#ffe066";
7522
+ SIDE_PLATFORM_BEVEL_COLOR = "rgba(255,255,255,0.15)";
7523
+ SIDE_PLATFORM_SHADOW_COLOR = "rgba(0,0,0,0.3)";
7524
+ SIDE_HAZARD_STRIPE_COLOR = "#e74c3c";
7525
+ SIDE_GOAL_GLOW_COLOR = "rgba(241, 196, 15, 0.5)";
7526
+ DEFAULT_BG_COLOR = "#5c94fc";
7469
7527
  }
7470
7528
  });
7471
7529
 
7472
7530
  // components/game/shared/spriteSheetConstants.ts
7473
- var SHEET_COLUMNS;
7531
+ var SHEET_COLUMNS, SPRITE_SHEET_LAYOUT;
7474
7532
  var init_spriteSheetConstants = __esm({
7475
7533
  "components/game/shared/spriteSheetConstants.ts"() {
7476
7534
  SHEET_COLUMNS = 8;
7535
+ SPRITE_SHEET_LAYOUT = {
7536
+ idle: { row: 0, frames: 4, frameRate: 6, loop: true },
7537
+ walk: { row: 1, frames: 8, frameRate: 10, loop: true },
7538
+ attack: { row: 2, frames: 6, frameRate: 12, loop: false },
7539
+ hit: { row: 3, frames: 3, frameRate: 8, loop: false },
7540
+ death: { row: 4, frames: 6, frameRate: 8, loop: false }
7541
+ };
7477
7542
  }
7478
7543
  });
7479
7544
 
@@ -10203,7 +10268,10 @@ var init_useUnitSpriteAtlas = __esm({
10203
10268
  init_spriteAnimation();
10204
10269
  }
10205
10270
  });
10206
- function SideView({
10271
+ function normalizeBackdrop(bg) {
10272
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10273
+ }
10274
+ function SideCanvas2D({
10207
10275
  player,
10208
10276
  platforms,
10209
10277
  worldWidth,
@@ -10212,7 +10280,7 @@ function SideView({
10212
10280
  canvasHeight,
10213
10281
  follow,
10214
10282
  bgColor,
10215
- backgroundImage,
10283
+ backgroundImage: backgroundImageRaw,
10216
10284
  playerSprite,
10217
10285
  tileSprites,
10218
10286
  effects,
@@ -10220,27 +10288,22 @@ function SideView({
10220
10288
  keyUpMap,
10221
10289
  className
10222
10290
  }) {
10291
+ const backgroundImage = normalizeBackdrop(backgroundImageRaw);
10223
10292
  const canvasRef = useRef(null);
10224
10293
  const eventBus = useEventBus();
10225
10294
  const keysRef = useRef(/* @__PURE__ */ new Set());
10226
- const imageCache2 = useRef(/* @__PURE__ */ new Map());
10227
- const [loadedImages, setLoadedImages] = useState(/* @__PURE__ */ new Set());
10228
- const loadImage = useCallback((url) => {
10229
- if (!url) return null;
10230
- const cached = imageCache2.current.get(url);
10231
- if (cached?.complete && cached.naturalWidth > 0) {
10232
- if (!loadedImages.has(url)) setLoadedImages((prev) => new Set(prev).add(url));
10233
- return cached;
10234
- }
10235
- if (!cached) {
10236
- const img = new Image();
10237
- img.crossOrigin = "anonymous";
10238
- img.src = url;
10239
- img.onload = () => setLoadedImages((prev) => new Set(prev).add(url));
10240
- imageCache2.current.set(url, img);
10295
+ const spriteUrls = useMemo(() => {
10296
+ const urls = [];
10297
+ if (backgroundImage?.url) urls.push(backgroundImage.url);
10298
+ if (playerSprite?.url) urls.push(playerSprite.url);
10299
+ if (tileSprites) {
10300
+ for (const asset of Object.values(tileSprites)) {
10301
+ if (asset?.url) urls.push(asset.url);
10302
+ }
10241
10303
  }
10242
- return null;
10243
- }, [loadedImages]);
10304
+ return urls;
10305
+ }, [backgroundImage, playerSprite, tileSprites]);
10306
+ const { getImage } = useImageCache(spriteUrls);
10244
10307
  useEffect(() => {
10245
10308
  if (typeof window === "undefined") return;
10246
10309
  const canvas = canvasRef.current;
@@ -10353,7 +10416,7 @@ function SideView({
10353
10416
  camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
10354
10417
  camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
10355
10418
  }
10356
- const bgImage = bgImg ? loadImage(bgImg.url) : null;
10419
+ const bgImage = bgImg ? getImage(bgImg.url) : void 0;
10357
10420
  const bgSrc = bgImage ? resolveAssetSource(bgImage, bgImg, NOOP) : null;
10358
10421
  if (bgSrc) {
10359
10422
  blit(ctx, bgSrc, 0, 0, cw, ch);
@@ -10364,12 +10427,12 @@ function SideView({
10364
10427
  ctx.fillRect(0, 0, cw, ch);
10365
10428
  } else {
10366
10429
  const grad = ctx.createLinearGradient(0, 0, 0, ch);
10367
- grad.addColorStop(0, SKY_GRADIENT_TOP);
10368
- grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
10430
+ grad.addColorStop(0, SIDE_SKY_GRADIENT_TOP);
10431
+ grad.addColorStop(1, SIDE_SKY_GRADIENT_BOTTOM);
10369
10432
  ctx.fillStyle = grad;
10370
10433
  ctx.fillRect(0, 0, cw, ch);
10371
10434
  }
10372
- ctx.strokeStyle = GRID_COLOR;
10435
+ ctx.strokeStyle = SIDE_GRID_COLOR;
10373
10436
  ctx.lineWidth = 1;
10374
10437
  const gridSize = 32;
10375
10438
  for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
@@ -10389,7 +10452,7 @@ function SideView({
10389
10452
  const platY = plat.y - camY;
10390
10453
  const platType = plat.type ?? "ground";
10391
10454
  const spriteAsset = tSprites?.[platType];
10392
- const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
10455
+ const tileImg = spriteAsset ? getImage(spriteAsset.url) : void 0;
10393
10456
  const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
10394
10457
  if (tileSrc) {
10395
10458
  const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
@@ -10404,15 +10467,15 @@ function SideView({
10404
10467
  ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
10405
10468
  }
10406
10469
  } else {
10407
- const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
10470
+ const color = SIDE_PLATFORM_COLORS[platType] ?? SIDE_PLATFORM_COLORS.ground;
10408
10471
  ctx.fillStyle = color;
10409
10472
  ctx.fillRect(platX, platY, plat.width, plat.height);
10410
- ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
10473
+ ctx.fillStyle = SIDE_PLATFORM_BEVEL_COLOR;
10411
10474
  ctx.fillRect(platX, platY, plat.width, 3);
10412
- ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
10475
+ ctx.fillStyle = SIDE_PLATFORM_SHADOW_COLOR;
10413
10476
  ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
10414
10477
  if (platType === "hazard") {
10415
- ctx.strokeStyle = "#e74c3c";
10478
+ ctx.strokeStyle = SIDE_HAZARD_STRIPE_COLOR;
10416
10479
  ctx.lineWidth = 2;
10417
10480
  for (let sx = platX; sx < platX + plat.width; sx += 12) {
10418
10481
  ctx.beginPath();
@@ -10422,7 +10485,7 @@ function SideView({
10422
10485
  }
10423
10486
  }
10424
10487
  if (platType === "goal") {
10425
- ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
10488
+ ctx.fillStyle = SIDE_GOAL_GLOW_COLOR;
10426
10489
  ctx.beginPath();
10427
10490
  ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
10428
10491
  ctx.fill();
@@ -10434,7 +10497,7 @@ function SideView({
10434
10497
  const ppx = px - camX;
10435
10498
  const ppy = py - camY;
10436
10499
  const facingRight = auth.facingRight ?? true;
10437
- const playerImg = pSprite ? loadImage(pSprite.url) : null;
10500
+ const playerImg = pSprite ? getImage(pSprite.url) : void 0;
10438
10501
  const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
10439
10502
  if (playerSrc) {
10440
10503
  ctx.save();
@@ -10447,7 +10510,7 @@ function SideView({
10447
10510
  }
10448
10511
  ctx.restore();
10449
10512
  } else {
10450
- ctx.fillStyle = PLAYER_COLOR;
10513
+ ctx.fillStyle = SIDE_PLAYER_COLOR;
10451
10514
  const radius = Math.min(pw, ph) * 0.25;
10452
10515
  ctx.beginPath();
10453
10516
  ctx.moveTo(ppx + radius, ppy);
@@ -10463,7 +10526,7 @@ function SideView({
10463
10526
  const eyeY = ppy + ph * 0.3;
10464
10527
  const eyeSize = 3;
10465
10528
  const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
10466
- ctx.fillStyle = PLAYER_EYE_COLOR;
10529
+ ctx.fillStyle = SIDE_PLAYER_EYE_COLOR;
10467
10530
  ctx.beginPath();
10468
10531
  ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
10469
10532
  ctx.fill();
@@ -10477,7 +10540,7 @@ function SideView({
10477
10540
  const alpha = Math.min(1, fx.ttl / 4);
10478
10541
  const prev = ctx.globalAlpha;
10479
10542
  ctx.globalAlpha = alpha;
10480
- ctx.fillStyle = "#ffe066";
10543
+ ctx.fillStyle = SIDE_FX_COLOR;
10481
10544
  ctx.beginPath();
10482
10545
  ctx.arc(fxScreenX, fxScreenY, 12, 0, Math.PI * 2);
10483
10546
  ctx.fill();
@@ -10485,7 +10548,7 @@ function SideView({
10485
10548
  }
10486
10549
  };
10487
10550
  return interp.startLoop(drawFrame);
10488
- }, [interp.startLoop, loadImage]);
10551
+ }, [interp.startLoop, getImage]);
10489
10552
  return /* @__PURE__ */ jsx(
10490
10553
  "canvas",
10491
10554
  {
@@ -10497,6 +10560,33 @@ function SideView({
10497
10560
  }
10498
10561
  );
10499
10562
  }
10563
+ var NOOP;
10564
+ var init_SideCanvas2D = __esm({
10565
+ "components/game/2d/molecules/SideCanvas2D.tsx"() {
10566
+ "use client";
10567
+ init_cn();
10568
+ init_useEventBus();
10569
+ init_useImageCache();
10570
+ init_atlasSlice();
10571
+ init_useRenderInterpolation();
10572
+ init_verificationRegistry();
10573
+ init_isometric();
10574
+ NOOP = () => {
10575
+ };
10576
+ SideCanvas2D.displayName = "SideCanvas2D";
10577
+ }
10578
+ });
10579
+ function normalizeBackdrop2(bg) {
10580
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10581
+ }
10582
+ function resolveTileFallbackColor(tile) {
10583
+ const override = tile.color;
10584
+ return override ?? TERRAIN_COLORS[tile.terrain ?? ""] ?? TERRAIN_COLORS.default;
10585
+ }
10586
+ function resolveUnitTeamColor(unit) {
10587
+ const override = unit.tint;
10588
+ return override ?? TEAM_COLORS[unit.team ?? ""] ?? TEAM_COLORS.default;
10589
+ }
10500
10590
  function Canvas2D({
10501
10591
  // Closed-circuit
10502
10592
  className,
@@ -10511,7 +10601,7 @@ function Canvas2D({
10511
10601
  effects: _effectsPropRaw = [],
10512
10602
  platforms,
10513
10603
  player,
10514
- backgroundImage,
10604
+ backgroundImage: backgroundImageRaw,
10515
10605
  // Interaction state
10516
10606
  selectedUnitId = null,
10517
10607
  validMoves = [],
@@ -10546,12 +10636,13 @@ function Canvas2D({
10546
10636
  // Side-view asset resolution
10547
10637
  playerSprite,
10548
10638
  tileSprites,
10549
- bgColor = "#5c94fc",
10639
+ bgColor = DEFAULT_BG_COLOR,
10550
10640
  worldWidth = 800,
10551
10641
  worldHeight = 400,
10552
10642
  // Remote asset loading
10553
10643
  assetManifest
10554
10644
  }) {
10645
+ const backgroundImage = normalizeBackdrop2(backgroundImageRaw);
10555
10646
  const isSide = projection === "side";
10556
10647
  const isFree = projection === "free";
10557
10648
  const flatLike = projection === "hex" || projection === "flat" || isFree;
@@ -10735,7 +10826,7 @@ function Canvas2D({
10735
10826
  return sortedTiles.map((t2) => ({
10736
10827
  x: t2.x,
10737
10828
  y: t2.y,
10738
- color: t2.terrain === "water" ? "#3b82f6" : t2.terrain === "mountain" ? "#78716c" : "#4ade80"
10829
+ color: MINIMAP_TERRAIN_COLORS[t2.terrain ?? ""] ?? MINIMAP_TERRAIN_COLORS.default
10739
10830
  }));
10740
10831
  }, [showMinimap, sortedTiles]);
10741
10832
  const miniMapUnits = useMemo(() => {
@@ -10743,7 +10834,7 @@ function Canvas2D({
10743
10834
  return units.filter((u) => u.position).map((u) => ({
10744
10835
  x: u.position.x,
10745
10836
  y: u.position.y,
10746
- color: u.team === "player" ? "#60a5fa" : u.team === "enemy" ? "#f87171" : "#9ca3af",
10837
+ color: MINIMAP_UNIT_COLORS[u.team ?? ""] ?? MINIMAP_UNIT_COLORS.default,
10747
10838
  isPlayer: u.team === "player"
10748
10839
  }));
10749
10840
  }, [showMinimap, units]);
@@ -10780,7 +10871,7 @@ function Canvas2D({
10780
10871
  }
10781
10872
  }
10782
10873
  } else {
10783
- ctx.fillStyle = "#1a1a2e";
10874
+ ctx.fillStyle = BACKGROUND_FALLBACK_COLOR;
10784
10875
  ctx.fillRect(0, 0, viewportSize.width, viewportSize.height);
10785
10876
  }
10786
10877
  if (sortedTiles.length === 0 && units.length === 0 && features.length === 0) return;
@@ -10810,15 +10901,15 @@ function Canvas2D({
10810
10901
  } else if (img && img.naturalWidth === 0) {
10811
10902
  ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10812
10903
  } else if (squareGrid) {
10813
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
10904
+ ctx.fillStyle = resolveTileFallbackColor(tile);
10814
10905
  ctx.fillRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
10815
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
10906
+ ctx.strokeStyle = GRID_STROKE_COLOR;
10816
10907
  ctx.lineWidth = 1;
10817
10908
  ctx.strokeRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
10818
10909
  } else {
10819
10910
  const centerX = pos.x + scaledTileWidth / 2;
10820
10911
  const topY = pos.y + scaledDiamondTopY;
10821
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
10912
+ ctx.fillStyle = resolveTileFallbackColor(tile);
10822
10913
  ctx.beginPath();
10823
10914
  ctx.moveTo(centerX, topY);
10824
10915
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -10826,7 +10917,7 @@ function Canvas2D({
10826
10917
  ctx.lineTo(pos.x, topY + scaledFloorHeight / 2);
10827
10918
  ctx.closePath();
10828
10919
  ctx.fill();
10829
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
10920
+ ctx.strokeStyle = GRID_STROKE_COLOR;
10830
10921
  ctx.lineWidth = 1;
10831
10922
  ctx.stroke();
10832
10923
  }
@@ -10847,11 +10938,11 @@ function Canvas2D({
10847
10938
  ctx.fill();
10848
10939
  };
10849
10940
  if (hoveredTile && hoveredTile.x === tile.x && hoveredTile.y === tile.y) {
10850
- drawHighlight("rgba(255, 255, 255, 0.15)");
10941
+ drawHighlight(HIGHLIGHT_COLORS.hover);
10851
10942
  }
10852
10943
  const tileKey = `${tile.x},${tile.y}`;
10853
- if (validMoveSet.has(tileKey)) drawHighlight("rgba(74, 222, 128, 0.25)");
10854
- if (attackTargetSet.has(tileKey)) drawHighlight("rgba(239, 68, 68, 0.35)");
10944
+ if (validMoveSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.validMove);
10945
+ if (attackTargetSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.attack);
10855
10946
  if (debug2) {
10856
10947
  const centerX = pos.x + scaledTileWidth / 2;
10857
10948
  const centerY = squareGrid ? pos.y + scaledTileWidth / 2 : pos.y + scaledFloorHeight / 2 + scaledDiamondTopY;
@@ -10925,9 +11016,9 @@ function Canvas2D({
10925
11016
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10926
11017
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
10927
11018
  const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
10928
- const SHEET_ROWS = 5;
10929
11019
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
10930
- const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11020
+ const sheetFrameH = img ? img.naturalHeight / LEGACY_SHEET_ROWS : 0;
11021
+ const legacyFrame = frameRect(0, 0, SHEET_COLUMNS, sheetFrameW, sheetFrameH);
10931
11022
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
10932
11023
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
10933
11024
  const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
@@ -10945,17 +11036,16 @@ function Canvas2D({
10945
11036
  ctx.globalAlpha = 0.25;
10946
11037
  if (img) {
10947
11038
  if (unitIsSheet) {
10948
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11039
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10949
11040
  } else if (unitSrc) {
10950
11041
  blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10951
11042
  } else {
10952
11043
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10953
11044
  }
10954
11045
  } else {
10955
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
10956
11046
  ctx.beginPath();
10957
11047
  ctx.arc(ghostCenterX, ghostGroundY - 16 * scale, 20 * scale, 0, Math.PI * 2);
10958
- ctx.fillStyle = color;
11048
+ ctx.fillStyle = resolveUnitTeamColor(unit);
10959
11049
  ctx.fill();
10960
11050
  }
10961
11051
  ctx.restore();
@@ -10963,7 +11053,7 @@ function Canvas2D({
10963
11053
  if (isSelected) {
10964
11054
  ctx.beginPath();
10965
11055
  ctx.ellipse(centerX, groundY, drawW / 2 + 4 * scale, 12 * scale, 0, 0, Math.PI * 2);
10966
- ctx.strokeStyle = "rgba(0, 200, 255, 0.8)";
11056
+ ctx.strokeStyle = SELECTION_RING_COLOR;
10967
11057
  ctx.lineWidth = 3;
10968
11058
  ctx.stroke();
10969
11059
  }
@@ -10980,7 +11070,7 @@ function Canvas2D({
10980
11070
  const spriteY = groundY - fDrawH - (frame.applyBreathing ? breatheOffset : 0);
10981
11071
  ctx.save();
10982
11072
  if (unit.team) {
10983
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11073
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
10984
11074
  ctx.shadowBlur = 12 * scale;
10985
11075
  }
10986
11076
  if (frame.flipX) {
@@ -10995,7 +11085,7 @@ function Canvas2D({
10995
11085
  const spriteY = groundY - drawH - breatheOffset;
10996
11086
  const drawUnit = (x) => {
10997
11087
  if (unitIsSheet) {
10998
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11088
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, x, spriteY, drawW, drawH);
10999
11089
  } else if (unitSrc) {
11000
11090
  blit(ctx, unitSrc, x, spriteY, drawW, drawH);
11001
11091
  } else {
@@ -11004,7 +11094,7 @@ function Canvas2D({
11004
11094
  };
11005
11095
  if (unit.team) {
11006
11096
  ctx.save();
11007
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11097
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
11008
11098
  ctx.shadowBlur = 12 * scale;
11009
11099
  drawUnit(centerX - drawW / 2);
11010
11100
  ctx.restore();
@@ -11012,10 +11102,9 @@ function Canvas2D({
11012
11102
  drawUnit(centerX - drawW / 2);
11013
11103
  }
11014
11104
  } else {
11015
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
11016
11105
  ctx.beginPath();
11017
11106
  ctx.arc(centerX, groundY - 20 * scale - breatheOffset, 20 * scale, 0, Math.PI * 2);
11018
- ctx.fillStyle = color;
11107
+ ctx.fillStyle = resolveUnitTeamColor(unit);
11019
11108
  ctx.fill();
11020
11109
  ctx.strokeStyle = "rgba(255,255,255,0.8)";
11021
11110
  ctx.lineWidth = 2;
@@ -11254,7 +11343,7 @@ function Canvas2D({
11254
11343
  }
11255
11344
  if (isSide) {
11256
11345
  return /* @__PURE__ */ jsx(Box, { ref: containerRef, className: cn("relative overflow-hidden w-full h-full", className), children: /* @__PURE__ */ jsx(
11257
- SideView,
11346
+ SideCanvas2D,
11258
11347
  {
11259
11348
  player,
11260
11349
  platforms: platforms && platforms.length ? platforms : DEFAULT_PLATFORMS,
@@ -11352,7 +11441,7 @@ function Canvas2D({
11352
11441
  {
11353
11442
  as: "span",
11354
11443
  className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap block",
11355
- 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)" },
11444
+ style: { background: UNIT_LABEL_BG_COLORS[unit.team ?? ""] ?? UNIT_LABEL_BG_COLORS.default },
11356
11445
  children: unit.name
11357
11446
  }
11358
11447
  ),
@@ -11376,7 +11465,7 @@ function Canvas2D({
11376
11465
  }
11377
11466
  );
11378
11467
  }
11379
- var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11468
+ var LEGACY_SHEET_ROWS, DEFAULT_PLATFORMS;
11380
11469
  var init_Canvas2D = __esm({
11381
11470
  "components/game/2d/molecules/Canvas2D.tsx"() {
11382
11471
  "use client";
@@ -11398,19 +11487,9 @@ var init_Canvas2D = __esm({
11398
11487
  init_verificationRegistry();
11399
11488
  init_isometric();
11400
11489
  init_spriteSheetConstants();
11401
- PLATFORM_COLORS = {
11402
- ground: "#4a7c59",
11403
- platform: "#7c6b4a",
11404
- hazard: "#c0392b",
11405
- goal: "#f1c40f"
11406
- };
11407
- NOOP = () => {
11408
- };
11409
- PLAYER_COLOR = "#3498db";
11410
- PLAYER_EYE_COLOR = "#ffffff";
11411
- SKY_GRADIENT_TOP = "#1a1a2e";
11412
- SKY_GRADIENT_BOTTOM = "#16213e";
11413
- GRID_COLOR = "rgba(255, 255, 255, 0.03)";
11490
+ init_spriteAnimation();
11491
+ init_SideCanvas2D();
11492
+ LEGACY_SHEET_ROWS = Object.keys(SPRITE_SHEET_LAYOUT).length;
11414
11493
  DEFAULT_PLATFORMS = [
11415
11494
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
11416
11495
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -17745,9 +17824,9 @@ var init_BiologyCanvas = __esm({
17745
17824
  }
17746
17825
  });
17747
17826
 
17748
- // node_modules/katex/dist/katex.min.css
17827
+ // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
17749
17828
  var init_katex_min = __esm({
17750
- "node_modules/katex/dist/katex.min.css"() {
17829
+ "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
17751
17830
  }
17752
17831
  });
17753
17832
  var Tabs;
@@ -29953,8 +30032,9 @@ var init_LineChart = __esm({
29953
30032
  const safeData = data ?? [];
29954
30033
  const sortedData = useMemo(() => {
29955
30034
  if (safeData.length === 0) return [];
30035
+ if (!safeData.some((d) => d.date != null)) return [...safeData];
29956
30036
  return [...safeData].sort(
29957
- (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
30037
+ (a, b) => new Date(a.date ?? 0).getTime() - new Date(b.date ?? 0).getTime()
29958
30038
  );
29959
30039
  }, [safeData]);
29960
30040
  const points = useMemo(() => {
@@ -30705,13 +30785,13 @@ var init_MapView = __esm({
30705
30785
  shadowSize: [41, 41]
30706
30786
  });
30707
30787
  L.Marker.prototype.options.icon = defaultIcon;
30708
- const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback103, useState: useState98 } = React98__default;
30788
+ const { useEffect: useEffect69, useRef: useRef66, useCallback: useCallback104, useState: useState98 } = React98__default;
30709
30789
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
30710
30790
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
30711
30791
  function MapUpdater({ centerLat, centerLng, zoom }) {
30712
30792
  const map = useMap();
30713
- const prevRef = useRef65({ centerLat, centerLng, zoom });
30714
- useEffect68(() => {
30793
+ const prevRef = useRef66({ centerLat, centerLng, zoom });
30794
+ useEffect69(() => {
30715
30795
  const prev = prevRef.current;
30716
30796
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
30717
30797
  map.setView([centerLat, centerLng], zoom);
@@ -30722,7 +30802,7 @@ var init_MapView = __esm({
30722
30802
  }
30723
30803
  function MapClickHandler({ onMapClick }) {
30724
30804
  const map = useMap();
30725
- useEffect68(() => {
30805
+ useEffect69(() => {
30726
30806
  if (!onMapClick) return;
30727
30807
  const handler = (e) => {
30728
30808
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -30751,7 +30831,7 @@ var init_MapView = __esm({
30751
30831
  }) {
30752
30832
  const eventBus = useEventBus2();
30753
30833
  const [clickedPosition, setClickedPosition] = useState98(null);
30754
- const handleMapClick = useCallback103((lat, lng) => {
30834
+ const handleMapClick = useCallback104((lat, lng) => {
30755
30835
  if (showClickedPin) {
30756
30836
  setClickedPosition({ lat, lng });
30757
30837
  }
@@ -30760,7 +30840,7 @@ var init_MapView = __esm({
30760
30840
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
30761
30841
  }
30762
30842
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
30763
- const handleMarkerClick = useCallback103((marker) => {
30843
+ const handleMarkerClick = useCallback104((marker) => {
30764
30844
  onMarkerClick?.(marker);
30765
30845
  if (markerClickEvent) {
30766
30846
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });