@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.
@@ -9616,6 +9616,76 @@ var init_StateGraph = __esm({
9616
9616
  init_TransitionArrow();
9617
9617
  }
9618
9618
  });
9619
+
9620
+ // components/game/shared/atlasSlice.ts
9621
+ function isTilesheet(a) {
9622
+ return typeof a.tileWidth === "number";
9623
+ }
9624
+ function getAtlas(url, onReady) {
9625
+ if (atlasCache.has(url)) return atlasCache.get(url) ?? void 0;
9626
+ atlasCache.set(url, void 0);
9627
+ fetch(url).then((r) => r.json()).then((json) => {
9628
+ atlasCache.set(url, json);
9629
+ onReady();
9630
+ }).catch(() => {
9631
+ atlasCache.set(url, null);
9632
+ });
9633
+ return void 0;
9634
+ }
9635
+ function subRectFor(atlas, sprite) {
9636
+ if (isTilesheet(atlas)) {
9637
+ let col;
9638
+ let row;
9639
+ if (sprite.includes(",")) {
9640
+ const [c, r] = sprite.split(",").map((n) => Number(n.trim()));
9641
+ col = c;
9642
+ row = r;
9643
+ } else {
9644
+ const i = Number(sprite);
9645
+ if (!Number.isFinite(i)) return null;
9646
+ col = i % atlas.columns;
9647
+ row = Math.floor(i / atlas.columns);
9648
+ }
9649
+ if (!Number.isFinite(col) || !Number.isFinite(row) || col < 0 || row < 0 || col >= atlas.columns || row >= atlas.rows) return null;
9650
+ const margin = atlas.margin ?? 0;
9651
+ const spacing = atlas.spacing ?? 0;
9652
+ return {
9653
+ sx: margin + col * (atlas.tileWidth + spacing),
9654
+ sy: margin + row * (atlas.tileHeight + spacing),
9655
+ sw: atlas.tileWidth,
9656
+ sh: atlas.tileHeight
9657
+ };
9658
+ }
9659
+ const st = atlas.subTextures[sprite];
9660
+ if (!st) return null;
9661
+ return { sx: st.x, sy: st.y, sw: st.width, sh: st.height };
9662
+ }
9663
+ function isAtlasAsset(asset) {
9664
+ return !!asset && typeof asset.atlas === "string" && typeof asset.sprite === "string";
9665
+ }
9666
+ function resolveAssetSource(img, asset, onReady) {
9667
+ if (isAtlasAsset(asset)) {
9668
+ const atlas = getAtlas(asset.atlas, onReady);
9669
+ if (!atlas) return null;
9670
+ const rect = subRectFor(atlas, asset.sprite);
9671
+ if (!rect) return null;
9672
+ return { img, rect, aspect: rect.sw / rect.sh };
9673
+ }
9674
+ const natW = img.naturalWidth || 1;
9675
+ const natH = img.naturalHeight || 1;
9676
+ return { img, rect: null, aspect: natW / natH };
9677
+ }
9678
+ function blit(ctx, src, dx, dy, dw, dh) {
9679
+ if (src.rect) ctx.drawImage(src.img, src.rect.sx, src.rect.sy, src.rect.sw, src.rect.sh, dx, dy, dw, dh);
9680
+ else ctx.drawImage(src.img, dx, dy, dw, dh);
9681
+ }
9682
+ var atlasCache;
9683
+ var init_atlasSlice = __esm({
9684
+ "components/game/shared/atlasSlice.ts"() {
9685
+ "use client";
9686
+ atlasCache = /* @__PURE__ */ new Map();
9687
+ }
9688
+ });
9619
9689
  function useCamera() {
9620
9690
  const cameraRef = useRef({ x: 0, y: 0, zoom: 1 });
9621
9691
  const targetCameraRef = useRef(null);
@@ -10187,15 +10257,18 @@ function SideView({
10187
10257
  const platType = plat.type ?? "ground";
10188
10258
  const spriteAsset = tSprites?.[platType];
10189
10259
  const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
10190
- if (tileImg) {
10191
- const tileW = tileImg.naturalWidth;
10192
- const tileH = tileImg.naturalHeight;
10260
+ const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
10261
+ if (tileSrc) {
10262
+ const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
10263
+ const originY = tileSrc.rect ? tileSrc.rect.sy : 0;
10264
+ const tileW = tileSrc.rect ? tileSrc.rect.sw : tileImg.naturalWidth;
10265
+ const tileH = tileSrc.rect ? tileSrc.rect.sh : tileImg.naturalHeight;
10193
10266
  const scaleH = plat.height / tileH;
10194
10267
  const scaledW = tileW * scaleH;
10195
10268
  for (let tx = 0; tx < plat.width; tx += scaledW) {
10196
10269
  const drawW = Math.min(scaledW, plat.width - tx);
10197
10270
  const srcW = drawW / scaleH;
10198
- ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
10271
+ ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
10199
10272
  }
10200
10273
  } else {
10201
10274
  const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
@@ -10229,14 +10302,15 @@ function SideView({
10229
10302
  const ppy = py - camY;
10230
10303
  const facingRight = auth.facingRight ?? true;
10231
10304
  const playerImg = pSprite ? loadImage(pSprite.url) : null;
10232
- if (playerImg) {
10305
+ const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
10306
+ if (playerSrc) {
10233
10307
  ctx.save();
10234
10308
  if (!facingRight) {
10235
10309
  ctx.translate(ppx + pw, ppy);
10236
10310
  ctx.scale(-1, 1);
10237
- ctx.drawImage(playerImg, 0, 0, pw, ph);
10311
+ blit(ctx, playerSrc, 0, 0, pw, ph);
10238
10312
  } else {
10239
- ctx.drawImage(playerImg, ppx, ppy, pw, ph);
10313
+ blit(ctx, playerSrc, ppx, ppy, pw, ph);
10240
10314
  }
10241
10315
  ctx.restore();
10242
10316
  } else {
@@ -10437,10 +10511,11 @@ function Canvas2D({
10437
10511
  const attackTargetSet = useMemo(() => new Set(attackTargets.map((p) => `${p.x},${p.y}`)), [attackTargets]);
10438
10512
  const spriteUrls = useMemo(() => {
10439
10513
  const urls = [];
10514
+ const toUrl = (x) => typeof x === "string" ? x : x?.url;
10440
10515
  for (const tile of sortedTiles) {
10441
10516
  if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
10442
10517
  else if (getTerrainSprite) {
10443
- const url = getTerrainSprite(tile.terrain ?? "");
10518
+ const url = toUrl(getTerrainSprite(tile.terrain ?? ""));
10444
10519
  if (url) urls.push(url);
10445
10520
  } else {
10446
10521
  const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
@@ -10450,7 +10525,7 @@ function Canvas2D({
10450
10525
  for (const feature of features) {
10451
10526
  if (feature.sprite) urls.push(feature.sprite.url);
10452
10527
  else if (getFeatureSprite) {
10453
- const url = getFeatureSprite(feature.type);
10528
+ const url = toUrl(getFeatureSprite(feature.type));
10454
10529
  if (url) urls.push(url);
10455
10530
  } else {
10456
10531
  const url = assetManifest?.features?.[feature.type]?.url;
@@ -10460,7 +10535,7 @@ function Canvas2D({
10460
10535
  for (const unit of units) {
10461
10536
  if (unit.sprite) urls.push(unit.sprite.url);
10462
10537
  else if (getUnitSprite) {
10463
- const url = getUnitSprite(unit);
10538
+ const url = toUrl(getUnitSprite(unit));
10464
10539
  if (url) urls.push(url);
10465
10540
  } else if (unit.unitType) {
10466
10541
  const url = assetManifest?.units?.[unit.unitType]?.url;
@@ -10501,14 +10576,25 @@ function Canvas2D({
10501
10576
  screenToWorld,
10502
10577
  lerpToTarget
10503
10578
  } = useCamera();
10504
- const resolveTerrainSpriteUrl = useCallback((tile) => {
10505
- return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
10579
+ const [, setAtlasVersion] = useState(0);
10580
+ const bumpAtlas = useCallback(() => setAtlasVersion((v) => v + 1), []);
10581
+ const resolveTerrainAsset = useCallback((tile) => {
10582
+ if (tile.terrainSprite) return tile.terrainSprite;
10583
+ const s = getTerrainSprite?.(tile.terrain ?? "");
10584
+ if (s) return typeof s === "string" ? { url: s } : s;
10585
+ return assetManifest?.terrains?.[tile.terrain ?? ""];
10506
10586
  }, [getTerrainSprite, assetManifest]);
10507
- const resolveFeatureSpriteUrl = useCallback((featureType) => {
10508
- return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
10587
+ const resolveFeatureAsset = useCallback((feature) => {
10588
+ if (feature.sprite) return feature.sprite;
10589
+ const s = getFeatureSprite?.(feature.type);
10590
+ if (s) return typeof s === "string" ? { url: s } : s;
10591
+ return assetManifest?.features?.[feature.type];
10509
10592
  }, [getFeatureSprite, assetManifest]);
10510
- const resolveUnitSpriteUrl = useCallback((unit) => {
10511
- return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
10593
+ const resolveUnitAsset = useCallback((unit) => {
10594
+ if (unit.sprite) return unit.sprite;
10595
+ const s = getUnitSprite?.(unit);
10596
+ if (s) return typeof s === "string" ? { url: s } : s;
10597
+ return unit.unitType ? assetManifest?.units?.[unit.unitType] : void 0;
10512
10598
  }, [getUnitSprite, assetManifest]);
10513
10599
  const miniMapTiles = useMemo(() => {
10514
10600
  if (!showMinimap) return [];
@@ -10572,18 +10658,17 @@ function Canvas2D({
10572
10658
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10573
10659
  continue;
10574
10660
  }
10575
- const spriteUrl = resolveTerrainSpriteUrl(tile);
10576
- const img = spriteUrl ? getImage(spriteUrl) : null;
10577
- if (img) {
10578
- if (img.naturalWidth === 0) {
10579
- ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10580
- } else {
10581
- const drawW = scaledTileWidth;
10582
- const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
10583
- const drawX = pos.x;
10584
- const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
10585
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
10586
- }
10661
+ const terrainAsset = resolveTerrainAsset(tile);
10662
+ const img = terrainAsset?.url ? getImage(terrainAsset.url) : null;
10663
+ const src = img ? resolveAssetSource(img, terrainAsset, bumpAtlas) : null;
10664
+ if (src) {
10665
+ const drawW = scaledTileWidth;
10666
+ const drawH = scaledTileWidth / src.aspect;
10667
+ const drawX = pos.x;
10668
+ const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
10669
+ blit(ctx, src, drawX, drawY, drawW, drawH);
10670
+ } else if (img && img.naturalWidth === 0) {
10671
+ ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10587
10672
  } else {
10588
10673
  const centerX = pos.x + scaledTileWidth / 2;
10589
10674
  const topY = pos.y + scaledDiamondTopY;
@@ -10637,15 +10722,16 @@ function Canvas2D({
10637
10722
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10638
10723
  continue;
10639
10724
  }
10640
- const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
10641
- const img = spriteUrl ? getImage(spriteUrl) : null;
10725
+ const featureAsset = resolveFeatureAsset(feature);
10726
+ const img = featureAsset?.url ? getImage(featureAsset.url) : null;
10727
+ const src = img ? resolveAssetSource(img, featureAsset, bumpAtlas) : null;
10642
10728
  const centerX = pos.x + scaledTileWidth / 2;
10643
10729
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
10644
10730
  const isCastle = feature.type === "castle";
10645
10731
  const featureDrawH = isCastle ? scaledFloorHeight * 3.5 : scaledFloorHeight * 1.6;
10646
10732
  const maxFeatureW = isCastle ? scaledTileWidth * 1.8 : scaledTileWidth * 0.7;
10647
- if (img) {
10648
- const ar = img.naturalWidth / img.naturalHeight;
10733
+ if (src) {
10734
+ const ar = src.aspect;
10649
10735
  let drawH = featureDrawH;
10650
10736
  let drawW = featureDrawH * ar;
10651
10737
  if (drawW > maxFeatureW) {
@@ -10654,7 +10740,7 @@ function Canvas2D({
10654
10740
  }
10655
10741
  const drawX = centerX - drawW / 2;
10656
10742
  const drawY = featureGroundY - drawH;
10657
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
10743
+ blit(ctx, src, drawX, drawY, drawW, drawH);
10658
10744
  } else {
10659
10745
  const color = FEATURE_COLORS[feature.type] || FEATURE_COLORS.default;
10660
10746
  ctx.beginPath();
@@ -10683,17 +10769,18 @@ function Canvas2D({
10683
10769
  const centerX = pos.x + scaledTileWidth / 2;
10684
10770
  const groundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
10685
10771
  const breatheOffset = 0;
10686
- const unitSpriteUrl = resolveUnitSpriteUrl(unit);
10687
- const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
10772
+ const unitAsset = resolveUnitAsset(unit);
10773
+ const img = unitAsset?.url ? getImage(unitAsset.url) : null;
10688
10774
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
10689
10775
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10690
10776
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
10777
+ const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
10691
10778
  const SHEET_ROWS = 5;
10692
10779
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
10693
10780
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
10694
10781
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
10695
10782
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
10696
- const ar = frameW / (frameH || 1);
10783
+ const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
10697
10784
  let drawH = unitDrawH;
10698
10785
  let drawW = unitDrawH * ar;
10699
10786
  if (drawW > maxUnitW) {
@@ -10709,6 +10796,8 @@ function Canvas2D({
10709
10796
  if (img) {
10710
10797
  if (unitIsSheet) {
10711
10798
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10799
+ } else if (unitSrc) {
10800
+ blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10712
10801
  } else {
10713
10802
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10714
10803
  }
@@ -10757,6 +10846,8 @@ function Canvas2D({
10757
10846
  const drawUnit = (x) => {
10758
10847
  if (unitIsSheet) {
10759
10848
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
10849
+ } else if (unitSrc) {
10850
+ blit(ctx, unitSrc, x, spriteY, drawW, drawH);
10760
10851
  } else {
10761
10852
  ctx.drawImage(img, x, spriteY, drawW, drawH);
10762
10853
  }
@@ -10807,11 +10898,12 @@ function Canvas2D({
10807
10898
  flatLike,
10808
10899
  scale,
10809
10900
  debug2,
10810
- resolveTerrainSpriteUrl,
10811
- resolveFeatureSpriteUrl,
10812
- resolveUnitSpriteUrl,
10901
+ resolveTerrainAsset,
10902
+ resolveFeatureAsset,
10903
+ resolveUnitAsset,
10813
10904
  resolveFrameForUnit,
10814
10905
  getImage,
10906
+ bumpAtlas,
10815
10907
  baseOffsetX,
10816
10908
  scaledTileWidth,
10817
10909
  scaledTileHeight,
@@ -11125,7 +11217,7 @@ function Canvas2D({
11125
11217
  }
11126
11218
  );
11127
11219
  }
11128
- var PLATFORM_COLORS, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11220
+ var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11129
11221
  var init_Canvas2D = __esm({
11130
11222
  "components/game/2d/molecules/Canvas2D.tsx"() {
11131
11223
  "use client";
@@ -11139,6 +11231,7 @@ var init_Canvas2D = __esm({
11139
11231
  init_MiniMap();
11140
11232
  init_HealthBar();
11141
11233
  init_useImageCache();
11234
+ init_atlasSlice();
11142
11235
  init_useCamera();
11143
11236
  init_useCanvasGestures();
11144
11237
  init_useRenderInterpolation();
@@ -11152,6 +11245,8 @@ var init_Canvas2D = __esm({
11152
11245
  hazard: "#c0392b",
11153
11246
  goal: "#f1c40f"
11154
11247
  };
11248
+ NOOP = () => {
11249
+ };
11155
11250
  PLAYER_COLOR = "#3498db";
11156
11251
  PLAYER_EYE_COLOR = "#ffffff";
11157
11252
  SKY_GRADIENT_TOP = "#1a1a2e";
@@ -16193,6 +16288,153 @@ var init_ComponentPatterns = __esm({
16193
16288
  AlertPattern.displayName = "AlertPattern";
16194
16289
  }
16195
16290
  });
16291
+ var DEFAULT_BAR_COLOR, DEFAULT_CELL_COLOR, DEFAULT_POINTER_COLOR, POINTER_BAND, TOP_PAD, AlgorithmCanvas;
16292
+ var init_AlgorithmCanvas = __esm({
16293
+ "components/learning/molecules/AlgorithmCanvas.tsx"() {
16294
+ "use client";
16295
+ init_atoms();
16296
+ init_Stack();
16297
+ init_LearningCanvas();
16298
+ DEFAULT_BAR_COLOR = "#3b82f6";
16299
+ DEFAULT_CELL_COLOR = "#e5e7eb";
16300
+ DEFAULT_POINTER_COLOR = "#dc2626";
16301
+ POINTER_BAND = 34;
16302
+ TOP_PAD = 12;
16303
+ AlgorithmCanvas = ({
16304
+ className,
16305
+ width = 600,
16306
+ height = 400,
16307
+ title,
16308
+ backgroundColor,
16309
+ bars = [],
16310
+ cells = [],
16311
+ pointers = [],
16312
+ shapes = [],
16313
+ interactive = false,
16314
+ animate = false,
16315
+ onShapeClick,
16316
+ isLoading,
16317
+ error
16318
+ }) => {
16319
+ const derivedShapes = useMemo(() => {
16320
+ const out = [];
16321
+ if (bars.length > 0) {
16322
+ const slot = width / bars.length;
16323
+ const barW = slot * 0.8;
16324
+ const gap = slot * 0.1;
16325
+ const baseline = height - POINTER_BAND;
16326
+ const usableH = baseline - TOP_PAD;
16327
+ const maxV = Math.max(1, ...bars.map((b) => Number.isFinite(b.value) ? b.value : 0));
16328
+ bars.forEach((bar, i) => {
16329
+ const v = Number.isFinite(bar.value) ? bar.value : 0;
16330
+ const bh = Math.max(0, v / maxV * usableH);
16331
+ const x = i * slot + gap;
16332
+ const color = bar.color ?? DEFAULT_BAR_COLOR;
16333
+ out.push({
16334
+ type: "rect",
16335
+ id: `bar-${i}`,
16336
+ x,
16337
+ y: baseline - bh,
16338
+ width: barW,
16339
+ height: bh,
16340
+ color,
16341
+ fill: color
16342
+ });
16343
+ const label = bar.label ?? (bars.length <= 24 ? String(v) : void 0);
16344
+ if (label) {
16345
+ out.push({
16346
+ type: "text",
16347
+ x: x + barW / 2,
16348
+ y: baseline - bh - 8,
16349
+ text: label,
16350
+ color: "#374151",
16351
+ fontSize: 11,
16352
+ align: "center"
16353
+ });
16354
+ }
16355
+ });
16356
+ pointers.forEach((p) => {
16357
+ if (p.index < 0 || p.index >= bars.length) return;
16358
+ const cx = p.index * slot + slot / 2;
16359
+ const color = p.color ?? DEFAULT_POINTER_COLOR;
16360
+ out.push({
16361
+ type: "arrow",
16362
+ x1: cx,
16363
+ y1: height - 6,
16364
+ x2: cx,
16365
+ y2: baseline + 4,
16366
+ color,
16367
+ lineWidth: 2
16368
+ });
16369
+ if (p.label) {
16370
+ out.push({
16371
+ type: "text",
16372
+ x: cx,
16373
+ y: height - 22,
16374
+ text: p.label,
16375
+ color,
16376
+ fontSize: 11,
16377
+ align: "center"
16378
+ });
16379
+ }
16380
+ });
16381
+ }
16382
+ if (cells.length > 0) {
16383
+ const maxCol = Math.max(0, ...cells.map((c) => c.col)) + 1;
16384
+ const maxRow = Math.max(0, ...cells.map((c) => c.row)) + 1;
16385
+ const cw = width / maxCol;
16386
+ const ch = height / maxRow;
16387
+ cells.forEach((c, i) => {
16388
+ const x = c.col * cw;
16389
+ const y = c.row * ch;
16390
+ const color = c.color ?? DEFAULT_CELL_COLOR;
16391
+ out.push({
16392
+ type: "rect",
16393
+ id: `cell-${i}`,
16394
+ x: x + 1,
16395
+ y: y + 1,
16396
+ width: cw - 2,
16397
+ height: ch - 2,
16398
+ color: "#9ca3af",
16399
+ fill: color
16400
+ });
16401
+ const label = c.label ?? (c.value != null ? String(c.value) : void 0);
16402
+ if (label && cw >= 18 && ch >= 14) {
16403
+ out.push({
16404
+ type: "text",
16405
+ x: x + cw / 2,
16406
+ y: y + ch / 2,
16407
+ text: label,
16408
+ color: "#111827",
16409
+ fontSize: 12,
16410
+ align: "center"
16411
+ });
16412
+ }
16413
+ });
16414
+ }
16415
+ out.push(...shapes);
16416
+ return out;
16417
+ }, [bars, cells, pointers, shapes, width, height]);
16418
+ return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
16419
+ title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
16420
+ /* @__PURE__ */ jsx(
16421
+ LearningCanvas,
16422
+ {
16423
+ width,
16424
+ height,
16425
+ backgroundColor,
16426
+ shapes: derivedShapes,
16427
+ interactive,
16428
+ animate,
16429
+ onShapeClick,
16430
+ isLoading,
16431
+ error
16432
+ }
16433
+ )
16434
+ ] }) });
16435
+ };
16436
+ }
16437
+ });
16196
16438
  var AuthLayout;
16197
16439
  var init_AuthLayout = __esm({
16198
16440
  "components/marketing/templates/AuthLayout.tsx"() {
@@ -45865,6 +46107,7 @@ var init_component_registry_generated = __esm({
45865
46107
  init_ActionTile();
45866
46108
  init_ActivationBlock();
45867
46109
  init_ComponentPatterns();
46110
+ init_AlgorithmCanvas();
45868
46111
  init_AnimatedCounter();
45869
46112
  init_AnimatedGraphic();
45870
46113
  init_AnimatedReveal();
@@ -46163,6 +46406,7 @@ var init_component_registry_generated = __esm({
46163
46406
  "ActivationBlock": ActivationBlock,
46164
46407
  "Alert": AlertPattern,
46165
46408
  "AlertPattern": AlertPattern,
46409
+ "AlgorithmCanvas": AlgorithmCanvas,
46166
46410
  "AnimatedCounter": AnimatedCounter,
46167
46411
  "AnimatedGraphic": AnimatedGraphic,
46168
46412
  "AnimatedReveal": AnimatedReveal,