@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
@@ -5,7 +5,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import * as LucideIcons2 from 'lucide-react';
6
6
  import { Loader2, X } from 'lucide-react';
7
7
 
8
- // node_modules/clsx/dist/clsx.mjs
8
+ // node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
9
9
  function r(e) {
10
10
  var t, f3, n = "";
11
11
  if ("string" == typeof e || "number" == typeof e) n += e;
@@ -20,7 +20,7 @@ function clsx() {
20
20
  return n;
21
21
  }
22
22
 
23
- // node_modules/tailwind-merge/dist/bundle-mjs.mjs
23
+ // node_modules/.pnpm/tailwind-merge@2.6.1/node_modules/tailwind-merge/dist/bundle-mjs.mjs
24
24
  var CLASS_PART_SEPARATOR = "-";
25
25
  var createClassGroupUtils = (config) => {
26
26
  const classMap = createClassMap(config);
@@ -43,5 +43,5 @@ interface EventBusProviderProps {
43
43
  */
44
44
  isolated?: boolean;
45
45
  }
46
- export declare function EventBusProvider({ children, isolated }: EventBusProviderProps): import("react/jsx-runtime").JSX.Element;
46
+ export declare function EventBusProvider({ children, isolated }: EventBusProviderProps): React.JSX.Element;
47
47
  export type { EventBusContextType };
@@ -50,7 +50,7 @@ interface SelectionProviderProps {
50
50
  * }
51
51
  * ```
52
52
  */
53
- export declare function SelectionProvider({ children, debug, compareEntities, }: SelectionProviderProps): import("react/jsx-runtime").JSX.Element;
53
+ export declare function SelectionProvider({ children, debug, compareEntities, }: SelectionProviderProps): React.JSX.Element;
54
54
  /**
55
55
  * Hook to access selection state.
56
56
  *
@@ -98,5 +98,5 @@ export interface ServerBridgeProviderProps {
98
98
  transport?: ServerBridgeTransport;
99
99
  children: ReactNode;
100
100
  }
101
- export declare function ServerBridgeProvider({ schema, serverUrl, transport: customTransport, children, }: ServerBridgeProviderProps): import("react/jsx-runtime").JSX.Element;
101
+ export declare function ServerBridgeProvider({ schema, serverUrl, transport: customTransport, children, }: ServerBridgeProviderProps): import("react").JSX.Element;
102
102
  export {};
@@ -7494,7 +7494,7 @@ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric")
7494
7494
  const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
7495
7495
  return { x: Math.round(tileX), y: Math.round(tileY) };
7496
7496
  }
7497
- var TILE_WIDTH, TILE_HEIGHT, FLOOR_HEIGHT, DIAMOND_TOP_Y, FEATURE_COLORS;
7497
+ 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;
7498
7498
  var init_isometric = __esm({
7499
7499
  "components/game/shared/isometric.ts"() {
7500
7500
  TILE_WIDTH = 256;
@@ -7511,14 +7511,79 @@ var init_isometric = __esm({
7511
7511
  mountain: "#78716c",
7512
7512
  default: "#9ca3af"
7513
7513
  };
7514
+ TERRAIN_COLORS = {
7515
+ water: "#3b82f6",
7516
+ mountain: "#78716c",
7517
+ stone: "#9ca3af",
7518
+ default: "#4ade80"
7519
+ };
7520
+ TEAM_COLORS = {
7521
+ player: "#3b82f6",
7522
+ enemy: "#ef4444",
7523
+ neutral: "#6b7280",
7524
+ default: "#6b7280"
7525
+ };
7526
+ TEAM_SHADOW_COLORS = {
7527
+ player: "rgba(0,150,255,0.6)",
7528
+ default: "rgba(255,50,50,0.6)"
7529
+ };
7530
+ HIGHLIGHT_COLORS = {
7531
+ hover: "rgba(255,255,255,0.15)",
7532
+ validMove: "rgba(74,222,128,0.25)",
7533
+ attack: "rgba(239,68,68,0.35)"
7534
+ };
7535
+ SELECTION_RING_COLOR = "rgba(0,200,255,0.8)";
7536
+ GRID_STROKE_COLOR = "rgba(0,0,0,0.2)";
7537
+ BACKGROUND_FALLBACK_COLOR = "#1a1a2e";
7538
+ MINIMAP_TERRAIN_COLORS = {
7539
+ water: "#3b82f6",
7540
+ mountain: "#78716c",
7541
+ default: "#4ade80"
7542
+ };
7543
+ MINIMAP_UNIT_COLORS = {
7544
+ player: "#60a5fa",
7545
+ enemy: "#f87171",
7546
+ neutral: "#9ca3af",
7547
+ default: "#9ca3af"
7548
+ };
7549
+ UNIT_LABEL_BG_COLORS = {
7550
+ player: "rgba(59,130,246,0.9)",
7551
+ enemy: "rgba(239,68,68,0.9)",
7552
+ neutral: "rgba(107,114,128,0.9)",
7553
+ default: "rgba(107,114,128,0.9)"
7554
+ };
7555
+ SIDE_PLATFORM_COLORS = {
7556
+ ground: "#4a7c59",
7557
+ platform: "#7c6b4a",
7558
+ hazard: "#c0392b",
7559
+ goal: "#f1c40f"
7560
+ };
7561
+ SIDE_PLAYER_COLOR = "#3498db";
7562
+ SIDE_PLAYER_EYE_COLOR = "#ffffff";
7563
+ SIDE_SKY_GRADIENT_TOP = "#1a1a2e";
7564
+ SIDE_SKY_GRADIENT_BOTTOM = "#16213e";
7565
+ SIDE_GRID_COLOR = "rgba(255, 255, 255, 0.03)";
7566
+ SIDE_FX_COLOR = "#ffe066";
7567
+ SIDE_PLATFORM_BEVEL_COLOR = "rgba(255,255,255,0.15)";
7568
+ SIDE_PLATFORM_SHADOW_COLOR = "rgba(0,0,0,0.3)";
7569
+ SIDE_HAZARD_STRIPE_COLOR = "#e74c3c";
7570
+ SIDE_GOAL_GLOW_COLOR = "rgba(241, 196, 15, 0.5)";
7571
+ DEFAULT_BG_COLOR = "#5c94fc";
7514
7572
  }
7515
7573
  });
7516
7574
 
7517
7575
  // components/game/shared/spriteSheetConstants.ts
7518
- var SHEET_COLUMNS;
7576
+ var SHEET_COLUMNS, SPRITE_SHEET_LAYOUT;
7519
7577
  var init_spriteSheetConstants = __esm({
7520
7578
  "components/game/shared/spriteSheetConstants.ts"() {
7521
7579
  SHEET_COLUMNS = 8;
7580
+ SPRITE_SHEET_LAYOUT = {
7581
+ idle: { row: 0, frames: 4, frameRate: 6, loop: true },
7582
+ walk: { row: 1, frames: 8, frameRate: 10, loop: true },
7583
+ attack: { row: 2, frames: 6, frameRate: 12, loop: false },
7584
+ hit: { row: 3, frames: 3, frameRate: 8, loop: false },
7585
+ death: { row: 4, frames: 6, frameRate: 8, loop: false }
7586
+ };
7522
7587
  }
7523
7588
  });
7524
7589
 
@@ -10248,7 +10313,10 @@ var init_useUnitSpriteAtlas = __esm({
10248
10313
  init_spriteAnimation();
10249
10314
  }
10250
10315
  });
10251
- function SideView({
10316
+ function normalizeBackdrop(bg) {
10317
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10318
+ }
10319
+ function SideCanvas2D({
10252
10320
  player,
10253
10321
  platforms,
10254
10322
  worldWidth,
@@ -10257,7 +10325,7 @@ function SideView({
10257
10325
  canvasHeight,
10258
10326
  follow,
10259
10327
  bgColor,
10260
- backgroundImage,
10328
+ backgroundImage: backgroundImageRaw,
10261
10329
  playerSprite,
10262
10330
  tileSprites,
10263
10331
  effects,
@@ -10265,27 +10333,22 @@ function SideView({
10265
10333
  keyUpMap,
10266
10334
  className
10267
10335
  }) {
10336
+ const backgroundImage = normalizeBackdrop(backgroundImageRaw);
10268
10337
  const canvasRef = React98.useRef(null);
10269
10338
  const eventBus = useEventBus();
10270
10339
  const keysRef = React98.useRef(/* @__PURE__ */ new Set());
10271
- const imageCache2 = React98.useRef(/* @__PURE__ */ new Map());
10272
- const [loadedImages, setLoadedImages] = React98.useState(/* @__PURE__ */ new Set());
10273
- const loadImage = React98.useCallback((url) => {
10274
- if (!url) return null;
10275
- const cached = imageCache2.current.get(url);
10276
- if (cached?.complete && cached.naturalWidth > 0) {
10277
- if (!loadedImages.has(url)) setLoadedImages((prev) => new Set(prev).add(url));
10278
- return cached;
10279
- }
10280
- if (!cached) {
10281
- const img = new Image();
10282
- img.crossOrigin = "anonymous";
10283
- img.src = url;
10284
- img.onload = () => setLoadedImages((prev) => new Set(prev).add(url));
10285
- imageCache2.current.set(url, img);
10340
+ const spriteUrls = React98.useMemo(() => {
10341
+ const urls = [];
10342
+ if (backgroundImage?.url) urls.push(backgroundImage.url);
10343
+ if (playerSprite?.url) urls.push(playerSprite.url);
10344
+ if (tileSprites) {
10345
+ for (const asset of Object.values(tileSprites)) {
10346
+ if (asset?.url) urls.push(asset.url);
10347
+ }
10286
10348
  }
10287
- return null;
10288
- }, [loadedImages]);
10349
+ return urls;
10350
+ }, [backgroundImage, playerSprite, tileSprites]);
10351
+ const { getImage } = useImageCache(spriteUrls);
10289
10352
  React98.useEffect(() => {
10290
10353
  if (typeof window === "undefined") return;
10291
10354
  const canvas = canvasRef.current;
@@ -10398,7 +10461,7 @@ function SideView({
10398
10461
  camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
10399
10462
  camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
10400
10463
  }
10401
- const bgImage = bgImg ? loadImage(bgImg.url) : null;
10464
+ const bgImage = bgImg ? getImage(bgImg.url) : void 0;
10402
10465
  const bgSrc = bgImage ? resolveAssetSource(bgImage, bgImg, NOOP) : null;
10403
10466
  if (bgSrc) {
10404
10467
  blit(ctx, bgSrc, 0, 0, cw, ch);
@@ -10409,12 +10472,12 @@ function SideView({
10409
10472
  ctx.fillRect(0, 0, cw, ch);
10410
10473
  } else {
10411
10474
  const grad = ctx.createLinearGradient(0, 0, 0, ch);
10412
- grad.addColorStop(0, SKY_GRADIENT_TOP);
10413
- grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
10475
+ grad.addColorStop(0, SIDE_SKY_GRADIENT_TOP);
10476
+ grad.addColorStop(1, SIDE_SKY_GRADIENT_BOTTOM);
10414
10477
  ctx.fillStyle = grad;
10415
10478
  ctx.fillRect(0, 0, cw, ch);
10416
10479
  }
10417
- ctx.strokeStyle = GRID_COLOR;
10480
+ ctx.strokeStyle = SIDE_GRID_COLOR;
10418
10481
  ctx.lineWidth = 1;
10419
10482
  const gridSize = 32;
10420
10483
  for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
@@ -10434,7 +10497,7 @@ function SideView({
10434
10497
  const platY = plat.y - camY;
10435
10498
  const platType = plat.type ?? "ground";
10436
10499
  const spriteAsset = tSprites?.[platType];
10437
- const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
10500
+ const tileImg = spriteAsset ? getImage(spriteAsset.url) : void 0;
10438
10501
  const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
10439
10502
  if (tileSrc) {
10440
10503
  const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
@@ -10449,15 +10512,15 @@ function SideView({
10449
10512
  ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
10450
10513
  }
10451
10514
  } else {
10452
- const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
10515
+ const color = SIDE_PLATFORM_COLORS[platType] ?? SIDE_PLATFORM_COLORS.ground;
10453
10516
  ctx.fillStyle = color;
10454
10517
  ctx.fillRect(platX, platY, plat.width, plat.height);
10455
- ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
10518
+ ctx.fillStyle = SIDE_PLATFORM_BEVEL_COLOR;
10456
10519
  ctx.fillRect(platX, platY, plat.width, 3);
10457
- ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
10520
+ ctx.fillStyle = SIDE_PLATFORM_SHADOW_COLOR;
10458
10521
  ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
10459
10522
  if (platType === "hazard") {
10460
- ctx.strokeStyle = "#e74c3c";
10523
+ ctx.strokeStyle = SIDE_HAZARD_STRIPE_COLOR;
10461
10524
  ctx.lineWidth = 2;
10462
10525
  for (let sx = platX; sx < platX + plat.width; sx += 12) {
10463
10526
  ctx.beginPath();
@@ -10467,7 +10530,7 @@ function SideView({
10467
10530
  }
10468
10531
  }
10469
10532
  if (platType === "goal") {
10470
- ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
10533
+ ctx.fillStyle = SIDE_GOAL_GLOW_COLOR;
10471
10534
  ctx.beginPath();
10472
10535
  ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
10473
10536
  ctx.fill();
@@ -10479,7 +10542,7 @@ function SideView({
10479
10542
  const ppx = px - camX;
10480
10543
  const ppy = py - camY;
10481
10544
  const facingRight = auth.facingRight ?? true;
10482
- const playerImg = pSprite ? loadImage(pSprite.url) : null;
10545
+ const playerImg = pSprite ? getImage(pSprite.url) : void 0;
10483
10546
  const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
10484
10547
  if (playerSrc) {
10485
10548
  ctx.save();
@@ -10492,7 +10555,7 @@ function SideView({
10492
10555
  }
10493
10556
  ctx.restore();
10494
10557
  } else {
10495
- ctx.fillStyle = PLAYER_COLOR;
10558
+ ctx.fillStyle = SIDE_PLAYER_COLOR;
10496
10559
  const radius = Math.min(pw, ph) * 0.25;
10497
10560
  ctx.beginPath();
10498
10561
  ctx.moveTo(ppx + radius, ppy);
@@ -10508,7 +10571,7 @@ function SideView({
10508
10571
  const eyeY = ppy + ph * 0.3;
10509
10572
  const eyeSize = 3;
10510
10573
  const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
10511
- ctx.fillStyle = PLAYER_EYE_COLOR;
10574
+ ctx.fillStyle = SIDE_PLAYER_EYE_COLOR;
10512
10575
  ctx.beginPath();
10513
10576
  ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
10514
10577
  ctx.fill();
@@ -10522,7 +10585,7 @@ function SideView({
10522
10585
  const alpha = Math.min(1, fx.ttl / 4);
10523
10586
  const prev = ctx.globalAlpha;
10524
10587
  ctx.globalAlpha = alpha;
10525
- ctx.fillStyle = "#ffe066";
10588
+ ctx.fillStyle = SIDE_FX_COLOR;
10526
10589
  ctx.beginPath();
10527
10590
  ctx.arc(fxScreenX, fxScreenY, 12, 0, Math.PI * 2);
10528
10591
  ctx.fill();
@@ -10530,7 +10593,7 @@ function SideView({
10530
10593
  }
10531
10594
  };
10532
10595
  return interp.startLoop(drawFrame);
10533
- }, [interp.startLoop, loadImage]);
10596
+ }, [interp.startLoop, getImage]);
10534
10597
  return /* @__PURE__ */ jsxRuntime.jsx(
10535
10598
  "canvas",
10536
10599
  {
@@ -10542,6 +10605,33 @@ function SideView({
10542
10605
  }
10543
10606
  );
10544
10607
  }
10608
+ var NOOP;
10609
+ var init_SideCanvas2D = __esm({
10610
+ "components/game/2d/molecules/SideCanvas2D.tsx"() {
10611
+ "use client";
10612
+ init_cn();
10613
+ init_useEventBus();
10614
+ init_useImageCache();
10615
+ init_atlasSlice();
10616
+ init_useRenderInterpolation();
10617
+ init_verificationRegistry();
10618
+ init_isometric();
10619
+ NOOP = () => {
10620
+ };
10621
+ SideCanvas2D.displayName = "SideCanvas2D";
10622
+ }
10623
+ });
10624
+ function normalizeBackdrop2(bg) {
10625
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10626
+ }
10627
+ function resolveTileFallbackColor(tile) {
10628
+ const override = tile.color;
10629
+ return override ?? TERRAIN_COLORS[tile.terrain ?? ""] ?? TERRAIN_COLORS.default;
10630
+ }
10631
+ function resolveUnitTeamColor(unit) {
10632
+ const override = unit.tint;
10633
+ return override ?? TEAM_COLORS[unit.team ?? ""] ?? TEAM_COLORS.default;
10634
+ }
10545
10635
  function Canvas2D({
10546
10636
  // Closed-circuit
10547
10637
  className,
@@ -10556,7 +10646,7 @@ function Canvas2D({
10556
10646
  effects: _effectsPropRaw = [],
10557
10647
  platforms,
10558
10648
  player,
10559
- backgroundImage,
10649
+ backgroundImage: backgroundImageRaw,
10560
10650
  // Interaction state
10561
10651
  selectedUnitId = null,
10562
10652
  validMoves = [],
@@ -10591,12 +10681,13 @@ function Canvas2D({
10591
10681
  // Side-view asset resolution
10592
10682
  playerSprite,
10593
10683
  tileSprites,
10594
- bgColor = "#5c94fc",
10684
+ bgColor = DEFAULT_BG_COLOR,
10595
10685
  worldWidth = 800,
10596
10686
  worldHeight = 400,
10597
10687
  // Remote asset loading
10598
10688
  assetManifest
10599
10689
  }) {
10690
+ const backgroundImage = normalizeBackdrop2(backgroundImageRaw);
10600
10691
  const isSide = projection === "side";
10601
10692
  const isFree = projection === "free";
10602
10693
  const flatLike = projection === "hex" || projection === "flat" || isFree;
@@ -10780,7 +10871,7 @@ function Canvas2D({
10780
10871
  return sortedTiles.map((t2) => ({
10781
10872
  x: t2.x,
10782
10873
  y: t2.y,
10783
- color: t2.terrain === "water" ? "#3b82f6" : t2.terrain === "mountain" ? "#78716c" : "#4ade80"
10874
+ color: MINIMAP_TERRAIN_COLORS[t2.terrain ?? ""] ?? MINIMAP_TERRAIN_COLORS.default
10784
10875
  }));
10785
10876
  }, [showMinimap, sortedTiles]);
10786
10877
  const miniMapUnits = React98.useMemo(() => {
@@ -10788,7 +10879,7 @@ function Canvas2D({
10788
10879
  return units.filter((u) => u.position).map((u) => ({
10789
10880
  x: u.position.x,
10790
10881
  y: u.position.y,
10791
- color: u.team === "player" ? "#60a5fa" : u.team === "enemy" ? "#f87171" : "#9ca3af",
10882
+ color: MINIMAP_UNIT_COLORS[u.team ?? ""] ?? MINIMAP_UNIT_COLORS.default,
10792
10883
  isPlayer: u.team === "player"
10793
10884
  }));
10794
10885
  }, [showMinimap, units]);
@@ -10825,7 +10916,7 @@ function Canvas2D({
10825
10916
  }
10826
10917
  }
10827
10918
  } else {
10828
- ctx.fillStyle = "#1a1a2e";
10919
+ ctx.fillStyle = BACKGROUND_FALLBACK_COLOR;
10829
10920
  ctx.fillRect(0, 0, viewportSize.width, viewportSize.height);
10830
10921
  }
10831
10922
  if (sortedTiles.length === 0 && units.length === 0 && features.length === 0) return;
@@ -10855,15 +10946,15 @@ function Canvas2D({
10855
10946
  } else if (img && img.naturalWidth === 0) {
10856
10947
  ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10857
10948
  } else if (squareGrid) {
10858
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
10949
+ ctx.fillStyle = resolveTileFallbackColor(tile);
10859
10950
  ctx.fillRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
10860
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
10951
+ ctx.strokeStyle = GRID_STROKE_COLOR;
10861
10952
  ctx.lineWidth = 1;
10862
10953
  ctx.strokeRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
10863
10954
  } else {
10864
10955
  const centerX = pos.x + scaledTileWidth / 2;
10865
10956
  const topY = pos.y + scaledDiamondTopY;
10866
- ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
10957
+ ctx.fillStyle = resolveTileFallbackColor(tile);
10867
10958
  ctx.beginPath();
10868
10959
  ctx.moveTo(centerX, topY);
10869
10960
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -10871,7 +10962,7 @@ function Canvas2D({
10871
10962
  ctx.lineTo(pos.x, topY + scaledFloorHeight / 2);
10872
10963
  ctx.closePath();
10873
10964
  ctx.fill();
10874
- ctx.strokeStyle = "rgba(0,0,0,0.2)";
10965
+ ctx.strokeStyle = GRID_STROKE_COLOR;
10875
10966
  ctx.lineWidth = 1;
10876
10967
  ctx.stroke();
10877
10968
  }
@@ -10892,11 +10983,11 @@ function Canvas2D({
10892
10983
  ctx.fill();
10893
10984
  };
10894
10985
  if (hoveredTile && hoveredTile.x === tile.x && hoveredTile.y === tile.y) {
10895
- drawHighlight("rgba(255, 255, 255, 0.15)");
10986
+ drawHighlight(HIGHLIGHT_COLORS.hover);
10896
10987
  }
10897
10988
  const tileKey = `${tile.x},${tile.y}`;
10898
- if (validMoveSet.has(tileKey)) drawHighlight("rgba(74, 222, 128, 0.25)");
10899
- if (attackTargetSet.has(tileKey)) drawHighlight("rgba(239, 68, 68, 0.35)");
10989
+ if (validMoveSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.validMove);
10990
+ if (attackTargetSet.has(tileKey)) drawHighlight(HIGHLIGHT_COLORS.attack);
10900
10991
  if (debug2) {
10901
10992
  const centerX = pos.x + scaledTileWidth / 2;
10902
10993
  const centerY = squareGrid ? pos.y + scaledTileWidth / 2 : pos.y + scaledFloorHeight / 2 + scaledDiamondTopY;
@@ -10970,9 +11061,9 @@ function Canvas2D({
10970
11061
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10971
11062
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
10972
11063
  const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
10973
- const SHEET_ROWS = 5;
10974
11064
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
10975
- const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11065
+ const sheetFrameH = img ? img.naturalHeight / LEGACY_SHEET_ROWS : 0;
11066
+ const legacyFrame = frameRect(0, 0, SHEET_COLUMNS, sheetFrameW, sheetFrameH);
10976
11067
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
10977
11068
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
10978
11069
  const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
@@ -10990,17 +11081,16 @@ function Canvas2D({
10990
11081
  ctx.globalAlpha = 0.25;
10991
11082
  if (img) {
10992
11083
  if (unitIsSheet) {
10993
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11084
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10994
11085
  } else if (unitSrc) {
10995
11086
  blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10996
11087
  } else {
10997
11088
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10998
11089
  }
10999
11090
  } else {
11000
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
11001
11091
  ctx.beginPath();
11002
11092
  ctx.arc(ghostCenterX, ghostGroundY - 16 * scale, 20 * scale, 0, Math.PI * 2);
11003
- ctx.fillStyle = color;
11093
+ ctx.fillStyle = resolveUnitTeamColor(unit);
11004
11094
  ctx.fill();
11005
11095
  }
11006
11096
  ctx.restore();
@@ -11008,7 +11098,7 @@ function Canvas2D({
11008
11098
  if (isSelected) {
11009
11099
  ctx.beginPath();
11010
11100
  ctx.ellipse(centerX, groundY, drawW / 2 + 4 * scale, 12 * scale, 0, 0, Math.PI * 2);
11011
- ctx.strokeStyle = "rgba(0, 200, 255, 0.8)";
11101
+ ctx.strokeStyle = SELECTION_RING_COLOR;
11012
11102
  ctx.lineWidth = 3;
11013
11103
  ctx.stroke();
11014
11104
  }
@@ -11025,7 +11115,7 @@ function Canvas2D({
11025
11115
  const spriteY = groundY - fDrawH - (frame.applyBreathing ? breatheOffset : 0);
11026
11116
  ctx.save();
11027
11117
  if (unit.team) {
11028
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11118
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
11029
11119
  ctx.shadowBlur = 12 * scale;
11030
11120
  }
11031
11121
  if (frame.flipX) {
@@ -11040,7 +11130,7 @@ function Canvas2D({
11040
11130
  const spriteY = groundY - drawH - breatheOffset;
11041
11131
  const drawUnit = (x) => {
11042
11132
  if (unitIsSheet) {
11043
- ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11133
+ ctx.drawImage(img, legacyFrame.sx, legacyFrame.sy, legacyFrame.sw, legacyFrame.sh, x, spriteY, drawW, drawH);
11044
11134
  } else if (unitSrc) {
11045
11135
  blit(ctx, unitSrc, x, spriteY, drawW, drawH);
11046
11136
  } else {
@@ -11049,7 +11139,7 @@ function Canvas2D({
11049
11139
  };
11050
11140
  if (unit.team) {
11051
11141
  ctx.save();
11052
- ctx.shadowColor = unit.team === "player" ? "rgba(0, 150, 255, 0.6)" : "rgba(255, 50, 50, 0.6)";
11142
+ ctx.shadowColor = TEAM_SHADOW_COLORS[unit.team] ?? TEAM_SHADOW_COLORS.default;
11053
11143
  ctx.shadowBlur = 12 * scale;
11054
11144
  drawUnit(centerX - drawW / 2);
11055
11145
  ctx.restore();
@@ -11057,10 +11147,9 @@ function Canvas2D({
11057
11147
  drawUnit(centerX - drawW / 2);
11058
11148
  }
11059
11149
  } else {
11060
- const color = unit.team === "player" ? "#3b82f6" : unit.team === "enemy" ? "#ef4444" : "#6b7280";
11061
11150
  ctx.beginPath();
11062
11151
  ctx.arc(centerX, groundY - 20 * scale - breatheOffset, 20 * scale, 0, Math.PI * 2);
11063
- ctx.fillStyle = color;
11152
+ ctx.fillStyle = resolveUnitTeamColor(unit);
11064
11153
  ctx.fill();
11065
11154
  ctx.strokeStyle = "rgba(255,255,255,0.8)";
11066
11155
  ctx.lineWidth = 2;
@@ -11299,7 +11388,7 @@ function Canvas2D({
11299
11388
  }
11300
11389
  if (isSide) {
11301
11390
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { ref: containerRef, className: cn("relative overflow-hidden w-full h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
11302
- SideView,
11391
+ SideCanvas2D,
11303
11392
  {
11304
11393
  player,
11305
11394
  platforms: platforms && platforms.length ? platforms : DEFAULT_PLATFORMS,
@@ -11397,7 +11486,7 @@ function Canvas2D({
11397
11486
  {
11398
11487
  as: "span",
11399
11488
  className: "text-white text-xs font-bold px-1.5 py-0.5 rounded mb-0.5 whitespace-nowrap block",
11400
- 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)" },
11489
+ style: { background: UNIT_LABEL_BG_COLORS[unit.team ?? ""] ?? UNIT_LABEL_BG_COLORS.default },
11401
11490
  children: unit.name
11402
11491
  }
11403
11492
  ),
@@ -11421,7 +11510,7 @@ function Canvas2D({
11421
11510
  }
11422
11511
  );
11423
11512
  }
11424
- var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11513
+ var LEGACY_SHEET_ROWS, DEFAULT_PLATFORMS;
11425
11514
  var init_Canvas2D = __esm({
11426
11515
  "components/game/2d/molecules/Canvas2D.tsx"() {
11427
11516
  "use client";
@@ -11443,19 +11532,9 @@ var init_Canvas2D = __esm({
11443
11532
  init_verificationRegistry();
11444
11533
  init_isometric();
11445
11534
  init_spriteSheetConstants();
11446
- PLATFORM_COLORS = {
11447
- ground: "#4a7c59",
11448
- platform: "#7c6b4a",
11449
- hazard: "#c0392b",
11450
- goal: "#f1c40f"
11451
- };
11452
- NOOP = () => {
11453
- };
11454
- PLAYER_COLOR = "#3498db";
11455
- PLAYER_EYE_COLOR = "#ffffff";
11456
- SKY_GRADIENT_TOP = "#1a1a2e";
11457
- SKY_GRADIENT_BOTTOM = "#16213e";
11458
- GRID_COLOR = "rgba(255, 255, 255, 0.03)";
11535
+ init_spriteAnimation();
11536
+ init_SideCanvas2D();
11537
+ LEGACY_SHEET_ROWS = Object.keys(SPRITE_SHEET_LAYOUT).length;
11459
11538
  DEFAULT_PLATFORMS = [
11460
11539
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
11461
11540
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -17790,9 +17869,9 @@ var init_BiologyCanvas = __esm({
17790
17869
  }
17791
17870
  });
17792
17871
 
17793
- // node_modules/katex/dist/katex.min.css
17872
+ // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
17794
17873
  var init_katex_min = __esm({
17795
- "node_modules/katex/dist/katex.min.css"() {
17874
+ "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
17796
17875
  }
17797
17876
  });
17798
17877
  var Tabs;
@@ -29998,8 +30077,9 @@ var init_LineChart = __esm({
29998
30077
  const safeData = data ?? [];
29999
30078
  const sortedData = React98.useMemo(() => {
30000
30079
  if (safeData.length === 0) return [];
30080
+ if (!safeData.some((d) => d.date != null)) return [...safeData];
30001
30081
  return [...safeData].sort(
30002
- (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
30082
+ (a, b) => new Date(a.date ?? 0).getTime() - new Date(b.date ?? 0).getTime()
30003
30083
  );
30004
30084
  }, [safeData]);
30005
30085
  const points = React98.useMemo(() => {
@@ -30750,13 +30830,13 @@ var init_MapView = __esm({
30750
30830
  shadowSize: [41, 41]
30751
30831
  });
30752
30832
  L.Marker.prototype.options.icon = defaultIcon;
30753
- const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback103, useState: useState98 } = React98__namespace.default;
30833
+ const { useEffect: useEffect69, useRef: useRef66, useCallback: useCallback104, useState: useState98 } = React98__namespace.default;
30754
30834
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
30755
30835
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
30756
30836
  function MapUpdater({ centerLat, centerLng, zoom }) {
30757
30837
  const map = useMap();
30758
- const prevRef = useRef65({ centerLat, centerLng, zoom });
30759
- useEffect68(() => {
30838
+ const prevRef = useRef66({ centerLat, centerLng, zoom });
30839
+ useEffect69(() => {
30760
30840
  const prev = prevRef.current;
30761
30841
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
30762
30842
  map.setView([centerLat, centerLng], zoom);
@@ -30767,7 +30847,7 @@ var init_MapView = __esm({
30767
30847
  }
30768
30848
  function MapClickHandler({ onMapClick }) {
30769
30849
  const map = useMap();
30770
- useEffect68(() => {
30850
+ useEffect69(() => {
30771
30851
  if (!onMapClick) return;
30772
30852
  const handler = (e) => {
30773
30853
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -30796,7 +30876,7 @@ var init_MapView = __esm({
30796
30876
  }) {
30797
30877
  const eventBus = useEventBus2();
30798
30878
  const [clickedPosition, setClickedPosition] = useState98(null);
30799
- const handleMapClick = useCallback103((lat, lng) => {
30879
+ const handleMapClick = useCallback104((lat, lng) => {
30800
30880
  if (showClickedPin) {
30801
30881
  setClickedPosition({ lat, lng });
30802
30882
  }
@@ -30805,7 +30885,7 @@ var init_MapView = __esm({
30805
30885
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
30806
30886
  }
30807
30887
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
30808
- const handleMarkerClick = useCallback103((marker) => {
30888
+ const handleMarkerClick = useCallback104((marker) => {
30809
30889
  onMarkerClick?.(marker);
30810
30890
  if (markerClickEvent) {
30811
30891
  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;