@almadar/ui 5.94.1 → 5.95.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.
@@ -13416,6 +13416,76 @@ var init_StateGraph = __esm({
13416
13416
  init_TransitionArrow();
13417
13417
  }
13418
13418
  });
13419
+
13420
+ // components/game/shared/atlasSlice.ts
13421
+ function isTilesheet(a) {
13422
+ return typeof a.tileWidth === "number";
13423
+ }
13424
+ function getAtlas(url, onReady) {
13425
+ if (atlasCache.has(url)) return atlasCache.get(url) ?? void 0;
13426
+ atlasCache.set(url, void 0);
13427
+ fetch(url).then((r2) => r2.json()).then((json) => {
13428
+ atlasCache.set(url, json);
13429
+ onReady();
13430
+ }).catch(() => {
13431
+ atlasCache.set(url, null);
13432
+ });
13433
+ return void 0;
13434
+ }
13435
+ function subRectFor(atlas, sprite) {
13436
+ if (isTilesheet(atlas)) {
13437
+ let col;
13438
+ let row;
13439
+ if (sprite.includes(",")) {
13440
+ const [c, r2] = sprite.split(",").map((n) => Number(n.trim()));
13441
+ col = c;
13442
+ row = r2;
13443
+ } else {
13444
+ const i = Number(sprite);
13445
+ if (!Number.isFinite(i)) return null;
13446
+ col = i % atlas.columns;
13447
+ row = Math.floor(i / atlas.columns);
13448
+ }
13449
+ if (!Number.isFinite(col) || !Number.isFinite(row) || col < 0 || row < 0 || col >= atlas.columns || row >= atlas.rows) return null;
13450
+ const margin = atlas.margin ?? 0;
13451
+ const spacing = atlas.spacing ?? 0;
13452
+ return {
13453
+ sx: margin + col * (atlas.tileWidth + spacing),
13454
+ sy: margin + row * (atlas.tileHeight + spacing),
13455
+ sw: atlas.tileWidth,
13456
+ sh: atlas.tileHeight
13457
+ };
13458
+ }
13459
+ const st = atlas.subTextures[sprite];
13460
+ if (!st) return null;
13461
+ return { sx: st.x, sy: st.y, sw: st.width, sh: st.height };
13462
+ }
13463
+ function isAtlasAsset(asset) {
13464
+ return !!asset && typeof asset.atlas === "string" && typeof asset.sprite === "string";
13465
+ }
13466
+ function resolveAssetSource(img, asset, onReady) {
13467
+ if (isAtlasAsset(asset)) {
13468
+ const atlas = getAtlas(asset.atlas, onReady);
13469
+ if (!atlas) return null;
13470
+ const rect = subRectFor(atlas, asset.sprite);
13471
+ if (!rect) return null;
13472
+ return { img, rect, aspect: rect.sw / rect.sh };
13473
+ }
13474
+ const natW = img.naturalWidth || 1;
13475
+ const natH = img.naturalHeight || 1;
13476
+ return { img, rect: null, aspect: natW / natH };
13477
+ }
13478
+ function blit(ctx, src, dx, dy, dw, dh) {
13479
+ if (src.rect) ctx.drawImage(src.img, src.rect.sx, src.rect.sy, src.rect.sw, src.rect.sh, dx, dy, dw, dh);
13480
+ else ctx.drawImage(src.img, dx, dy, dw, dh);
13481
+ }
13482
+ var atlasCache;
13483
+ var init_atlasSlice = __esm({
13484
+ "components/game/shared/atlasSlice.ts"() {
13485
+ "use client";
13486
+ atlasCache = /* @__PURE__ */ new Map();
13487
+ }
13488
+ });
13419
13489
  function useCamera() {
13420
13490
  const cameraRef = React104.useRef({ x: 0, y: 0, zoom: 1 });
13421
13491
  const targetCameraRef = React104.useRef(null);
@@ -13987,15 +14057,18 @@ function SideView({
13987
14057
  const platType = plat.type ?? "ground";
13988
14058
  const spriteAsset = tSprites?.[platType];
13989
14059
  const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
13990
- if (tileImg) {
13991
- const tileW = tileImg.naturalWidth;
13992
- const tileH = tileImg.naturalHeight;
14060
+ const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
14061
+ if (tileSrc) {
14062
+ const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
14063
+ const originY = tileSrc.rect ? tileSrc.rect.sy : 0;
14064
+ const tileW = tileSrc.rect ? tileSrc.rect.sw : tileImg.naturalWidth;
14065
+ const tileH = tileSrc.rect ? tileSrc.rect.sh : tileImg.naturalHeight;
13993
14066
  const scaleH = plat.height / tileH;
13994
14067
  const scaledW = tileW * scaleH;
13995
14068
  for (let tx = 0; tx < plat.width; tx += scaledW) {
13996
14069
  const drawW = Math.min(scaledW, plat.width - tx);
13997
14070
  const srcW = drawW / scaleH;
13998
- ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
14071
+ ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
13999
14072
  }
14000
14073
  } else {
14001
14074
  const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
@@ -14029,14 +14102,15 @@ function SideView({
14029
14102
  const ppy = py - camY;
14030
14103
  const facingRight = auth.facingRight ?? true;
14031
14104
  const playerImg = pSprite ? loadImage(pSprite.url) : null;
14032
- if (playerImg) {
14105
+ const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
14106
+ if (playerSrc) {
14033
14107
  ctx.save();
14034
14108
  if (!facingRight) {
14035
14109
  ctx.translate(ppx + pw, ppy);
14036
14110
  ctx.scale(-1, 1);
14037
- ctx.drawImage(playerImg, 0, 0, pw, ph);
14111
+ blit(ctx, playerSrc, 0, 0, pw, ph);
14038
14112
  } else {
14039
- ctx.drawImage(playerImg, ppx, ppy, pw, ph);
14113
+ blit(ctx, playerSrc, ppx, ppy, pw, ph);
14040
14114
  }
14041
14115
  ctx.restore();
14042
14116
  } else {
@@ -14237,10 +14311,11 @@ function Canvas2D({
14237
14311
  const attackTargetSet = React104.useMemo(() => new Set(attackTargets.map((p) => `${p.x},${p.y}`)), [attackTargets]);
14238
14312
  const spriteUrls = React104.useMemo(() => {
14239
14313
  const urls = [];
14314
+ const toUrl = (x) => typeof x === "string" ? x : x?.url;
14240
14315
  for (const tile of sortedTiles) {
14241
14316
  if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
14242
14317
  else if (getTerrainSprite) {
14243
- const url = getTerrainSprite(tile.terrain ?? "");
14318
+ const url = toUrl(getTerrainSprite(tile.terrain ?? ""));
14244
14319
  if (url) urls.push(url);
14245
14320
  } else {
14246
14321
  const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
@@ -14250,7 +14325,7 @@ function Canvas2D({
14250
14325
  for (const feature of features) {
14251
14326
  if (feature.sprite) urls.push(feature.sprite.url);
14252
14327
  else if (getFeatureSprite) {
14253
- const url = getFeatureSprite(feature.type);
14328
+ const url = toUrl(getFeatureSprite(feature.type));
14254
14329
  if (url) urls.push(url);
14255
14330
  } else {
14256
14331
  const url = assetManifest?.features?.[feature.type]?.url;
@@ -14260,7 +14335,7 @@ function Canvas2D({
14260
14335
  for (const unit of units) {
14261
14336
  if (unit.sprite) urls.push(unit.sprite.url);
14262
14337
  else if (getUnitSprite) {
14263
- const url = getUnitSprite(unit);
14338
+ const url = toUrl(getUnitSprite(unit));
14264
14339
  if (url) urls.push(url);
14265
14340
  } else if (unit.unitType) {
14266
14341
  const url = assetManifest?.units?.[unit.unitType]?.url;
@@ -14301,14 +14376,25 @@ function Canvas2D({
14301
14376
  screenToWorld,
14302
14377
  lerpToTarget
14303
14378
  } = useCamera();
14304
- const resolveTerrainSpriteUrl = React104.useCallback((tile) => {
14305
- return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
14379
+ const [, setAtlasVersion] = React104.useState(0);
14380
+ const bumpAtlas = React104.useCallback(() => setAtlasVersion((v) => v + 1), []);
14381
+ const resolveTerrainAsset = React104.useCallback((tile) => {
14382
+ if (tile.terrainSprite) return tile.terrainSprite;
14383
+ const s = getTerrainSprite?.(tile.terrain ?? "");
14384
+ if (s) return typeof s === "string" ? { url: s } : s;
14385
+ return assetManifest?.terrains?.[tile.terrain ?? ""];
14306
14386
  }, [getTerrainSprite, assetManifest]);
14307
- const resolveFeatureSpriteUrl = React104.useCallback((featureType) => {
14308
- return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
14387
+ const resolveFeatureAsset = React104.useCallback((feature) => {
14388
+ if (feature.sprite) return feature.sprite;
14389
+ const s = getFeatureSprite?.(feature.type);
14390
+ if (s) return typeof s === "string" ? { url: s } : s;
14391
+ return assetManifest?.features?.[feature.type];
14309
14392
  }, [getFeatureSprite, assetManifest]);
14310
- const resolveUnitSpriteUrl = React104.useCallback((unit) => {
14311
- return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
14393
+ const resolveUnitAsset = React104.useCallback((unit) => {
14394
+ if (unit.sprite) return unit.sprite;
14395
+ const s = getUnitSprite?.(unit);
14396
+ if (s) return typeof s === "string" ? { url: s } : s;
14397
+ return unit.unitType ? assetManifest?.units?.[unit.unitType] : void 0;
14312
14398
  }, [getUnitSprite, assetManifest]);
14313
14399
  const miniMapTiles = React104.useMemo(() => {
14314
14400
  if (!showMinimap) return [];
@@ -14372,18 +14458,17 @@ function Canvas2D({
14372
14458
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
14373
14459
  continue;
14374
14460
  }
14375
- const spriteUrl = resolveTerrainSpriteUrl(tile);
14376
- const img = spriteUrl ? getImage(spriteUrl) : null;
14377
- if (img) {
14378
- if (img.naturalWidth === 0) {
14379
- ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
14380
- } else {
14381
- const drawW = scaledTileWidth;
14382
- const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
14383
- const drawX = pos.x;
14384
- const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
14385
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
14386
- }
14461
+ const terrainAsset = resolveTerrainAsset(tile);
14462
+ const img = terrainAsset?.url ? getImage(terrainAsset.url) : null;
14463
+ const src = img ? resolveAssetSource(img, terrainAsset, bumpAtlas) : null;
14464
+ if (src) {
14465
+ const drawW = scaledTileWidth;
14466
+ const drawH = scaledTileWidth / src.aspect;
14467
+ const drawX = pos.x;
14468
+ const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
14469
+ blit(ctx, src, drawX, drawY, drawW, drawH);
14470
+ } else if (img && img.naturalWidth === 0) {
14471
+ ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
14387
14472
  } else {
14388
14473
  const centerX = pos.x + scaledTileWidth / 2;
14389
14474
  const topY = pos.y + scaledDiamondTopY;
@@ -14437,15 +14522,16 @@ function Canvas2D({
14437
14522
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
14438
14523
  continue;
14439
14524
  }
14440
- const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
14441
- const img = spriteUrl ? getImage(spriteUrl) : null;
14525
+ const featureAsset = resolveFeatureAsset(feature);
14526
+ const img = featureAsset?.url ? getImage(featureAsset.url) : null;
14527
+ const src = img ? resolveAssetSource(img, featureAsset, bumpAtlas) : null;
14442
14528
  const centerX = pos.x + scaledTileWidth / 2;
14443
14529
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
14444
14530
  const isCastle = feature.type === "castle";
14445
14531
  const featureDrawH = isCastle ? scaledFloorHeight * 3.5 : scaledFloorHeight * 1.6;
14446
14532
  const maxFeatureW = isCastle ? scaledTileWidth * 1.8 : scaledTileWidth * 0.7;
14447
- if (img) {
14448
- const ar = img.naturalWidth / img.naturalHeight;
14533
+ if (src) {
14534
+ const ar = src.aspect;
14449
14535
  let drawH = featureDrawH;
14450
14536
  let drawW = featureDrawH * ar;
14451
14537
  if (drawW > maxFeatureW) {
@@ -14454,7 +14540,7 @@ function Canvas2D({
14454
14540
  }
14455
14541
  const drawX = centerX - drawW / 2;
14456
14542
  const drawY = featureGroundY - drawH;
14457
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
14543
+ blit(ctx, src, drawX, drawY, drawW, drawH);
14458
14544
  } else {
14459
14545
  const color = FEATURE_COLORS[feature.type] || FEATURE_COLORS.default;
14460
14546
  ctx.beginPath();
@@ -14483,17 +14569,18 @@ function Canvas2D({
14483
14569
  const centerX = pos.x + scaledTileWidth / 2;
14484
14570
  const groundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
14485
14571
  const breatheOffset = 0;
14486
- const unitSpriteUrl = resolveUnitSpriteUrl(unit);
14487
- const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
14572
+ const unitAsset = resolveUnitAsset(unit);
14573
+ const img = unitAsset?.url ? getImage(unitAsset.url) : null;
14488
14574
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
14489
14575
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
14490
14576
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
14577
+ const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
14491
14578
  const SHEET_ROWS = 5;
14492
14579
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
14493
14580
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
14494
14581
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
14495
14582
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
14496
- const ar = frameW / (frameH || 1);
14583
+ const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
14497
14584
  let drawH = unitDrawH;
14498
14585
  let drawW = unitDrawH * ar;
14499
14586
  if (drawW > maxUnitW) {
@@ -14509,6 +14596,8 @@ function Canvas2D({
14509
14596
  if (img) {
14510
14597
  if (unitIsSheet) {
14511
14598
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
14599
+ } else if (unitSrc) {
14600
+ blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
14512
14601
  } else {
14513
14602
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
14514
14603
  }
@@ -14557,6 +14646,8 @@ function Canvas2D({
14557
14646
  const drawUnit = (x) => {
14558
14647
  if (unitIsSheet) {
14559
14648
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
14649
+ } else if (unitSrc) {
14650
+ blit(ctx, unitSrc, x, spriteY, drawW, drawH);
14560
14651
  } else {
14561
14652
  ctx.drawImage(img, x, spriteY, drawW, drawH);
14562
14653
  }
@@ -14607,11 +14698,12 @@ function Canvas2D({
14607
14698
  flatLike,
14608
14699
  scale,
14609
14700
  debug2,
14610
- resolveTerrainSpriteUrl,
14611
- resolveFeatureSpriteUrl,
14612
- resolveUnitSpriteUrl,
14701
+ resolveTerrainAsset,
14702
+ resolveFeatureAsset,
14703
+ resolveUnitAsset,
14613
14704
  resolveFrameForUnit,
14614
14705
  getImage,
14706
+ bumpAtlas,
14615
14707
  baseOffsetX,
14616
14708
  scaledTileWidth,
14617
14709
  scaledTileHeight,
@@ -14925,7 +15017,7 @@ function Canvas2D({
14925
15017
  }
14926
15018
  );
14927
15019
  }
14928
- var PLATFORM_COLORS, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
15020
+ var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
14929
15021
  var init_Canvas2D = __esm({
14930
15022
  "components/game/2d/molecules/Canvas2D.tsx"() {
14931
15023
  "use client";
@@ -14939,6 +15031,7 @@ var init_Canvas2D = __esm({
14939
15031
  init_MiniMap();
14940
15032
  init_HealthBar();
14941
15033
  init_useImageCache();
15034
+ init_atlasSlice();
14942
15035
  init_useCamera();
14943
15036
  init_useCanvasGestures();
14944
15037
  init_useRenderInterpolation();
@@ -14952,6 +15045,8 @@ var init_Canvas2D = __esm({
14952
15045
  hazard: "#c0392b",
14953
15046
  goal: "#f1c40f"
14954
15047
  };
15048
+ NOOP = () => {
15049
+ };
14955
15050
  PLAYER_COLOR = "#3498db";
14956
15051
  PLAYER_EYE_COLOR = "#ffffff";
14957
15052
  SKY_GRADIENT_TOP = "#1a1a2e";
@@ -19610,6 +19705,153 @@ var init_ComponentPatterns = __esm({
19610
19705
  AlertPattern.displayName = "AlertPattern";
19611
19706
  }
19612
19707
  });
19708
+ var DEFAULT_BAR_COLOR, DEFAULT_CELL_COLOR, DEFAULT_POINTER_COLOR, POINTER_BAND, TOP_PAD, AlgorithmCanvas;
19709
+ var init_AlgorithmCanvas = __esm({
19710
+ "components/learning/molecules/AlgorithmCanvas.tsx"() {
19711
+ "use client";
19712
+ init_atoms();
19713
+ init_Stack();
19714
+ init_LearningCanvas();
19715
+ DEFAULT_BAR_COLOR = "#3b82f6";
19716
+ DEFAULT_CELL_COLOR = "#e5e7eb";
19717
+ DEFAULT_POINTER_COLOR = "#dc2626";
19718
+ POINTER_BAND = 34;
19719
+ TOP_PAD = 12;
19720
+ AlgorithmCanvas = ({
19721
+ className,
19722
+ width = 600,
19723
+ height = 400,
19724
+ title,
19725
+ backgroundColor,
19726
+ bars = [],
19727
+ cells = [],
19728
+ pointers = [],
19729
+ shapes = [],
19730
+ interactive = false,
19731
+ animate = false,
19732
+ onShapeClick,
19733
+ isLoading,
19734
+ error
19735
+ }) => {
19736
+ const derivedShapes = React104.useMemo(() => {
19737
+ const out = [];
19738
+ if (bars.length > 0) {
19739
+ const slot = width / bars.length;
19740
+ const barW = slot * 0.8;
19741
+ const gap = slot * 0.1;
19742
+ const baseline = height - POINTER_BAND;
19743
+ const usableH = baseline - TOP_PAD;
19744
+ const maxV = Math.max(1, ...bars.map((b) => Number.isFinite(b.value) ? b.value : 0));
19745
+ bars.forEach((bar, i) => {
19746
+ const v = Number.isFinite(bar.value) ? bar.value : 0;
19747
+ const bh = Math.max(0, v / maxV * usableH);
19748
+ const x = i * slot + gap;
19749
+ const color = bar.color ?? DEFAULT_BAR_COLOR;
19750
+ out.push({
19751
+ type: "rect",
19752
+ id: `bar-${i}`,
19753
+ x,
19754
+ y: baseline - bh,
19755
+ width: barW,
19756
+ height: bh,
19757
+ color,
19758
+ fill: color
19759
+ });
19760
+ const label = bar.label ?? (bars.length <= 24 ? String(v) : void 0);
19761
+ if (label) {
19762
+ out.push({
19763
+ type: "text",
19764
+ x: x + barW / 2,
19765
+ y: baseline - bh - 8,
19766
+ text: label,
19767
+ color: "#374151",
19768
+ fontSize: 11,
19769
+ align: "center"
19770
+ });
19771
+ }
19772
+ });
19773
+ pointers.forEach((p) => {
19774
+ if (p.index < 0 || p.index >= bars.length) return;
19775
+ const cx = p.index * slot + slot / 2;
19776
+ const color = p.color ?? DEFAULT_POINTER_COLOR;
19777
+ out.push({
19778
+ type: "arrow",
19779
+ x1: cx,
19780
+ y1: height - 6,
19781
+ x2: cx,
19782
+ y2: baseline + 4,
19783
+ color,
19784
+ lineWidth: 2
19785
+ });
19786
+ if (p.label) {
19787
+ out.push({
19788
+ type: "text",
19789
+ x: cx,
19790
+ y: height - 22,
19791
+ text: p.label,
19792
+ color,
19793
+ fontSize: 11,
19794
+ align: "center"
19795
+ });
19796
+ }
19797
+ });
19798
+ }
19799
+ if (cells.length > 0) {
19800
+ const maxCol = Math.max(0, ...cells.map((c) => c.col)) + 1;
19801
+ const maxRow = Math.max(0, ...cells.map((c) => c.row)) + 1;
19802
+ const cw = width / maxCol;
19803
+ const ch = height / maxRow;
19804
+ cells.forEach((c, i) => {
19805
+ const x = c.col * cw;
19806
+ const y = c.row * ch;
19807
+ const color = c.color ?? DEFAULT_CELL_COLOR;
19808
+ out.push({
19809
+ type: "rect",
19810
+ id: `cell-${i}`,
19811
+ x: x + 1,
19812
+ y: y + 1,
19813
+ width: cw - 2,
19814
+ height: ch - 2,
19815
+ color: "#9ca3af",
19816
+ fill: color
19817
+ });
19818
+ const label = c.label ?? (c.value != null ? String(c.value) : void 0);
19819
+ if (label && cw >= 18 && ch >= 14) {
19820
+ out.push({
19821
+ type: "text",
19822
+ x: x + cw / 2,
19823
+ y: y + ch / 2,
19824
+ text: label,
19825
+ color: "#111827",
19826
+ fontSize: 12,
19827
+ align: "center"
19828
+ });
19829
+ }
19830
+ });
19831
+ }
19832
+ out.push(...shapes);
19833
+ return out;
19834
+ }, [bars, cells, pointers, shapes, width, height]);
19835
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
19836
+ title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
19837
+ /* @__PURE__ */ jsxRuntime.jsx(
19838
+ LearningCanvas,
19839
+ {
19840
+ width,
19841
+ height,
19842
+ backgroundColor,
19843
+ shapes: derivedShapes,
19844
+ interactive,
19845
+ animate,
19846
+ onShapeClick,
19847
+ isLoading,
19848
+ error
19849
+ }
19850
+ )
19851
+ ] }) });
19852
+ };
19853
+ }
19854
+ });
19613
19855
  var AuthLayout;
19614
19856
  var init_AuthLayout = __esm({
19615
19857
  "components/marketing/templates/AuthLayout.tsx"() {
@@ -48065,6 +48307,7 @@ var init_component_registry_generated = __esm({
48065
48307
  init_ActionTile();
48066
48308
  init_ActivationBlock();
48067
48309
  init_ComponentPatterns();
48310
+ init_AlgorithmCanvas();
48068
48311
  init_AnimatedCounter();
48069
48312
  init_AnimatedGraphic();
48070
48313
  init_AnimatedReveal();
@@ -48363,6 +48606,7 @@ var init_component_registry_generated = __esm({
48363
48606
  "ActivationBlock": ActivationBlock,
48364
48607
  "Alert": AlertPattern,
48365
48608
  "AlertPattern": AlertPattern,
48609
+ "AlgorithmCanvas": AlgorithmCanvas,
48366
48610
  "AnimatedCounter": AnimatedCounter,
48367
48611
  "AnimatedGraphic": AnimatedGraphic,
48368
48612
  "AnimatedReveal": AnimatedReveal,