@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.
@@ -10142,6 +10142,76 @@ var init_StateGraph = __esm({
10142
10142
  init_TransitionArrow();
10143
10143
  }
10144
10144
  });
10145
+
10146
+ // components/game/shared/atlasSlice.ts
10147
+ function isTilesheet(a) {
10148
+ return typeof a.tileWidth === "number";
10149
+ }
10150
+ function getAtlas(url, onReady) {
10151
+ if (atlasCache.has(url)) return atlasCache.get(url) ?? void 0;
10152
+ atlasCache.set(url, void 0);
10153
+ fetch(url).then((r) => r.json()).then((json) => {
10154
+ atlasCache.set(url, json);
10155
+ onReady();
10156
+ }).catch(() => {
10157
+ atlasCache.set(url, null);
10158
+ });
10159
+ return void 0;
10160
+ }
10161
+ function subRectFor(atlas, sprite) {
10162
+ if (isTilesheet(atlas)) {
10163
+ let col;
10164
+ let row;
10165
+ if (sprite.includes(",")) {
10166
+ const [c, r] = sprite.split(",").map((n) => Number(n.trim()));
10167
+ col = c;
10168
+ row = r;
10169
+ } else {
10170
+ const i = Number(sprite);
10171
+ if (!Number.isFinite(i)) return null;
10172
+ col = i % atlas.columns;
10173
+ row = Math.floor(i / atlas.columns);
10174
+ }
10175
+ if (!Number.isFinite(col) || !Number.isFinite(row) || col < 0 || row < 0 || col >= atlas.columns || row >= atlas.rows) return null;
10176
+ const margin = atlas.margin ?? 0;
10177
+ const spacing = atlas.spacing ?? 0;
10178
+ return {
10179
+ sx: margin + col * (atlas.tileWidth + spacing),
10180
+ sy: margin + row * (atlas.tileHeight + spacing),
10181
+ sw: atlas.tileWidth,
10182
+ sh: atlas.tileHeight
10183
+ };
10184
+ }
10185
+ const st = atlas.subTextures[sprite];
10186
+ if (!st) return null;
10187
+ return { sx: st.x, sy: st.y, sw: st.width, sh: st.height };
10188
+ }
10189
+ function isAtlasAsset(asset) {
10190
+ return !!asset && typeof asset.atlas === "string" && typeof asset.sprite === "string";
10191
+ }
10192
+ function resolveAssetSource(img, asset, onReady) {
10193
+ if (isAtlasAsset(asset)) {
10194
+ const atlas = getAtlas(asset.atlas, onReady);
10195
+ if (!atlas) return null;
10196
+ const rect = subRectFor(atlas, asset.sprite);
10197
+ if (!rect) return null;
10198
+ return { img, rect, aspect: rect.sw / rect.sh };
10199
+ }
10200
+ const natW = img.naturalWidth || 1;
10201
+ const natH = img.naturalHeight || 1;
10202
+ return { img, rect: null, aspect: natW / natH };
10203
+ }
10204
+ function blit(ctx, src, dx, dy, dw, dh) {
10205
+ if (src.rect) ctx.drawImage(src.img, src.rect.sx, src.rect.sy, src.rect.sw, src.rect.sh, dx, dy, dw, dh);
10206
+ else ctx.drawImage(src.img, dx, dy, dw, dh);
10207
+ }
10208
+ var atlasCache;
10209
+ var init_atlasSlice = __esm({
10210
+ "components/game/shared/atlasSlice.ts"() {
10211
+ "use client";
10212
+ atlasCache = /* @__PURE__ */ new Map();
10213
+ }
10214
+ });
10145
10215
  function useCamera() {
10146
10216
  const cameraRef = useRef({ x: 0, y: 0, zoom: 1 });
10147
10217
  const targetCameraRef = useRef(null);
@@ -10534,15 +10604,18 @@ function SideView({
10534
10604
  const platType = plat.type ?? "ground";
10535
10605
  const spriteAsset = tSprites?.[platType];
10536
10606
  const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
10537
- if (tileImg) {
10538
- const tileW = tileImg.naturalWidth;
10539
- const tileH = tileImg.naturalHeight;
10607
+ const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
10608
+ if (tileSrc) {
10609
+ const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
10610
+ const originY = tileSrc.rect ? tileSrc.rect.sy : 0;
10611
+ const tileW = tileSrc.rect ? tileSrc.rect.sw : tileImg.naturalWidth;
10612
+ const tileH = tileSrc.rect ? tileSrc.rect.sh : tileImg.naturalHeight;
10540
10613
  const scaleH = plat.height / tileH;
10541
10614
  const scaledW = tileW * scaleH;
10542
10615
  for (let tx = 0; tx < plat.width; tx += scaledW) {
10543
10616
  const drawW = Math.min(scaledW, plat.width - tx);
10544
10617
  const srcW = drawW / scaleH;
10545
- ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
10618
+ ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
10546
10619
  }
10547
10620
  } else {
10548
10621
  const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
@@ -10576,14 +10649,15 @@ function SideView({
10576
10649
  const ppy = py - camY;
10577
10650
  const facingRight = auth.facingRight ?? true;
10578
10651
  const playerImg = pSprite ? loadImage(pSprite.url) : null;
10579
- if (playerImg) {
10652
+ const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
10653
+ if (playerSrc) {
10580
10654
  ctx.save();
10581
10655
  if (!facingRight) {
10582
10656
  ctx.translate(ppx + pw, ppy);
10583
10657
  ctx.scale(-1, 1);
10584
- ctx.drawImage(playerImg, 0, 0, pw, ph);
10658
+ blit(ctx, playerSrc, 0, 0, pw, ph);
10585
10659
  } else {
10586
- ctx.drawImage(playerImg, ppx, ppy, pw, ph);
10660
+ blit(ctx, playerSrc, ppx, ppy, pw, ph);
10587
10661
  }
10588
10662
  ctx.restore();
10589
10663
  } else {
@@ -10784,10 +10858,11 @@ function Canvas2D({
10784
10858
  const attackTargetSet = useMemo(() => new Set(attackTargets.map((p) => `${p.x},${p.y}`)), [attackTargets]);
10785
10859
  const spriteUrls = useMemo(() => {
10786
10860
  const urls = [];
10861
+ const toUrl = (x) => typeof x === "string" ? x : x?.url;
10787
10862
  for (const tile of sortedTiles) {
10788
10863
  if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
10789
10864
  else if (getTerrainSprite) {
10790
- const url = getTerrainSprite(tile.terrain ?? "");
10865
+ const url = toUrl(getTerrainSprite(tile.terrain ?? ""));
10791
10866
  if (url) urls.push(url);
10792
10867
  } else {
10793
10868
  const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
@@ -10797,7 +10872,7 @@ function Canvas2D({
10797
10872
  for (const feature of features) {
10798
10873
  if (feature.sprite) urls.push(feature.sprite.url);
10799
10874
  else if (getFeatureSprite) {
10800
- const url = getFeatureSprite(feature.type);
10875
+ const url = toUrl(getFeatureSprite(feature.type));
10801
10876
  if (url) urls.push(url);
10802
10877
  } else {
10803
10878
  const url = assetManifest?.features?.[feature.type]?.url;
@@ -10807,7 +10882,7 @@ function Canvas2D({
10807
10882
  for (const unit of units) {
10808
10883
  if (unit.sprite) urls.push(unit.sprite.url);
10809
10884
  else if (getUnitSprite) {
10810
- const url = getUnitSprite(unit);
10885
+ const url = toUrl(getUnitSprite(unit));
10811
10886
  if (url) urls.push(url);
10812
10887
  } else if (unit.unitType) {
10813
10888
  const url = assetManifest?.units?.[unit.unitType]?.url;
@@ -10848,14 +10923,25 @@ function Canvas2D({
10848
10923
  screenToWorld,
10849
10924
  lerpToTarget
10850
10925
  } = useCamera();
10851
- const resolveTerrainSpriteUrl = useCallback((tile) => {
10852
- return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
10926
+ const [, setAtlasVersion] = useState(0);
10927
+ const bumpAtlas = useCallback(() => setAtlasVersion((v) => v + 1), []);
10928
+ const resolveTerrainAsset = useCallback((tile) => {
10929
+ if (tile.terrainSprite) return tile.terrainSprite;
10930
+ const s = getTerrainSprite?.(tile.terrain ?? "");
10931
+ if (s) return typeof s === "string" ? { url: s } : s;
10932
+ return assetManifest?.terrains?.[tile.terrain ?? ""];
10853
10933
  }, [getTerrainSprite, assetManifest]);
10854
- const resolveFeatureSpriteUrl = useCallback((featureType) => {
10855
- return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
10934
+ const resolveFeatureAsset = useCallback((feature) => {
10935
+ if (feature.sprite) return feature.sprite;
10936
+ const s = getFeatureSprite?.(feature.type);
10937
+ if (s) return typeof s === "string" ? { url: s } : s;
10938
+ return assetManifest?.features?.[feature.type];
10856
10939
  }, [getFeatureSprite, assetManifest]);
10857
- const resolveUnitSpriteUrl = useCallback((unit) => {
10858
- return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
10940
+ const resolveUnitAsset = useCallback((unit) => {
10941
+ if (unit.sprite) return unit.sprite;
10942
+ const s = getUnitSprite?.(unit);
10943
+ if (s) return typeof s === "string" ? { url: s } : s;
10944
+ return unit.unitType ? assetManifest?.units?.[unit.unitType] : void 0;
10859
10945
  }, [getUnitSprite, assetManifest]);
10860
10946
  const miniMapTiles = useMemo(() => {
10861
10947
  if (!showMinimap) return [];
@@ -10919,18 +11005,17 @@ function Canvas2D({
10919
11005
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10920
11006
  continue;
10921
11007
  }
10922
- const spriteUrl = resolveTerrainSpriteUrl(tile);
10923
- const img = spriteUrl ? getImage(spriteUrl) : null;
10924
- if (img) {
10925
- if (img.naturalWidth === 0) {
10926
- ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10927
- } else {
10928
- const drawW = scaledTileWidth;
10929
- const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
10930
- const drawX = pos.x;
10931
- const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
10932
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
10933
- }
11008
+ const terrainAsset = resolveTerrainAsset(tile);
11009
+ const img = terrainAsset?.url ? getImage(terrainAsset.url) : null;
11010
+ const src = img ? resolveAssetSource(img, terrainAsset, bumpAtlas) : null;
11011
+ if (src) {
11012
+ const drawW = scaledTileWidth;
11013
+ const drawH = scaledTileWidth / src.aspect;
11014
+ const drawX = pos.x;
11015
+ const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
11016
+ blit(ctx, src, drawX, drawY, drawW, drawH);
11017
+ } else if (img && img.naturalWidth === 0) {
11018
+ ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
10934
11019
  } else {
10935
11020
  const centerX = pos.x + scaledTileWidth / 2;
10936
11021
  const topY = pos.y + scaledDiamondTopY;
@@ -10984,15 +11069,16 @@ function Canvas2D({
10984
11069
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10985
11070
  continue;
10986
11071
  }
10987
- const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
10988
- const img = spriteUrl ? getImage(spriteUrl) : null;
11072
+ const featureAsset = resolveFeatureAsset(feature);
11073
+ const img = featureAsset?.url ? getImage(featureAsset.url) : null;
11074
+ const src = img ? resolveAssetSource(img, featureAsset, bumpAtlas) : null;
10989
11075
  const centerX = pos.x + scaledTileWidth / 2;
10990
11076
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
10991
11077
  const isCastle = feature.type === "castle";
10992
11078
  const featureDrawH = isCastle ? scaledFloorHeight * 3.5 : scaledFloorHeight * 1.6;
10993
11079
  const maxFeatureW = isCastle ? scaledTileWidth * 1.8 : scaledTileWidth * 0.7;
10994
- if (img) {
10995
- const ar = img.naturalWidth / img.naturalHeight;
11080
+ if (src) {
11081
+ const ar = src.aspect;
10996
11082
  let drawH = featureDrawH;
10997
11083
  let drawW = featureDrawH * ar;
10998
11084
  if (drawW > maxFeatureW) {
@@ -11001,7 +11087,7 @@ function Canvas2D({
11001
11087
  }
11002
11088
  const drawX = centerX - drawW / 2;
11003
11089
  const drawY = featureGroundY - drawH;
11004
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
11090
+ blit(ctx, src, drawX, drawY, drawW, drawH);
11005
11091
  } else {
11006
11092
  const color = FEATURE_COLORS[feature.type] || FEATURE_COLORS.default;
11007
11093
  ctx.beginPath();
@@ -11030,17 +11116,18 @@ function Canvas2D({
11030
11116
  const centerX = pos.x + scaledTileWidth / 2;
11031
11117
  const groundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
11032
11118
  const breatheOffset = 0;
11033
- const unitSpriteUrl = resolveUnitSpriteUrl(unit);
11034
- const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
11119
+ const unitAsset = resolveUnitAsset(unit);
11120
+ const img = unitAsset?.url ? getImage(unitAsset.url) : null;
11035
11121
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
11036
11122
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11037
11123
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
11124
+ const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
11038
11125
  const SHEET_ROWS = 5;
11039
11126
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
11040
11127
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11041
11128
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11042
11129
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11043
- const ar = frameW / (frameH || 1);
11130
+ const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
11044
11131
  let drawH = unitDrawH;
11045
11132
  let drawW = unitDrawH * ar;
11046
11133
  if (drawW > maxUnitW) {
@@ -11056,6 +11143,8 @@ function Canvas2D({
11056
11143
  if (img) {
11057
11144
  if (unitIsSheet) {
11058
11145
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11146
+ } else if (unitSrc) {
11147
+ blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11059
11148
  } else {
11060
11149
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11061
11150
  }
@@ -11104,6 +11193,8 @@ function Canvas2D({
11104
11193
  const drawUnit = (x) => {
11105
11194
  if (unitIsSheet) {
11106
11195
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11196
+ } else if (unitSrc) {
11197
+ blit(ctx, unitSrc, x, spriteY, drawW, drawH);
11107
11198
  } else {
11108
11199
  ctx.drawImage(img, x, spriteY, drawW, drawH);
11109
11200
  }
@@ -11154,11 +11245,12 @@ function Canvas2D({
11154
11245
  flatLike,
11155
11246
  scale,
11156
11247
  debug2,
11157
- resolveTerrainSpriteUrl,
11158
- resolveFeatureSpriteUrl,
11159
- resolveUnitSpriteUrl,
11248
+ resolveTerrainAsset,
11249
+ resolveFeatureAsset,
11250
+ resolveUnitAsset,
11160
11251
  resolveFrameForUnit,
11161
11252
  getImage,
11253
+ bumpAtlas,
11162
11254
  baseOffsetX,
11163
11255
  scaledTileWidth,
11164
11256
  scaledTileHeight,
@@ -11472,7 +11564,7 @@ function Canvas2D({
11472
11564
  }
11473
11565
  );
11474
11566
  }
11475
- var PLATFORM_COLORS, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11567
+ var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
11476
11568
  var init_Canvas2D = __esm({
11477
11569
  "components/game/2d/molecules/Canvas2D.tsx"() {
11478
11570
  "use client";
@@ -11486,6 +11578,7 @@ var init_Canvas2D = __esm({
11486
11578
  init_MiniMap();
11487
11579
  init_HealthBar();
11488
11580
  init_useImageCache();
11581
+ init_atlasSlice();
11489
11582
  init_useCamera();
11490
11583
  init_useCanvasGestures();
11491
11584
  init_useRenderInterpolation();
@@ -11499,6 +11592,8 @@ var init_Canvas2D = __esm({
11499
11592
  hazard: "#c0392b",
11500
11593
  goal: "#f1c40f"
11501
11594
  };
11595
+ NOOP = () => {
11596
+ };
11502
11597
  PLAYER_COLOR = "#3498db";
11503
11598
  PLAYER_EYE_COLOR = "#ffffff";
11504
11599
  SKY_GRADIENT_TOP = "#1a1a2e";
@@ -16157,6 +16252,153 @@ var init_ComponentPatterns = __esm({
16157
16252
  AlertPattern.displayName = "AlertPattern";
16158
16253
  }
16159
16254
  });
16255
+ var DEFAULT_BAR_COLOR, DEFAULT_CELL_COLOR, DEFAULT_POINTER_COLOR, POINTER_BAND, TOP_PAD, AlgorithmCanvas;
16256
+ var init_AlgorithmCanvas = __esm({
16257
+ "components/learning/molecules/AlgorithmCanvas.tsx"() {
16258
+ "use client";
16259
+ init_atoms();
16260
+ init_Stack();
16261
+ init_LearningCanvas();
16262
+ DEFAULT_BAR_COLOR = "#3b82f6";
16263
+ DEFAULT_CELL_COLOR = "#e5e7eb";
16264
+ DEFAULT_POINTER_COLOR = "#dc2626";
16265
+ POINTER_BAND = 34;
16266
+ TOP_PAD = 12;
16267
+ AlgorithmCanvas = ({
16268
+ className,
16269
+ width = 600,
16270
+ height = 400,
16271
+ title,
16272
+ backgroundColor,
16273
+ bars = [],
16274
+ cells = [],
16275
+ pointers = [],
16276
+ shapes = [],
16277
+ interactive = false,
16278
+ animate = false,
16279
+ onShapeClick,
16280
+ isLoading,
16281
+ error
16282
+ }) => {
16283
+ const derivedShapes = useMemo(() => {
16284
+ const out = [];
16285
+ if (bars.length > 0) {
16286
+ const slot = width / bars.length;
16287
+ const barW = slot * 0.8;
16288
+ const gap = slot * 0.1;
16289
+ const baseline = height - POINTER_BAND;
16290
+ const usableH = baseline - TOP_PAD;
16291
+ const maxV = Math.max(1, ...bars.map((b) => Number.isFinite(b.value) ? b.value : 0));
16292
+ bars.forEach((bar, i) => {
16293
+ const v = Number.isFinite(bar.value) ? bar.value : 0;
16294
+ const bh = Math.max(0, v / maxV * usableH);
16295
+ const x = i * slot + gap;
16296
+ const color = bar.color ?? DEFAULT_BAR_COLOR;
16297
+ out.push({
16298
+ type: "rect",
16299
+ id: `bar-${i}`,
16300
+ x,
16301
+ y: baseline - bh,
16302
+ width: barW,
16303
+ height: bh,
16304
+ color,
16305
+ fill: color
16306
+ });
16307
+ const label = bar.label ?? (bars.length <= 24 ? String(v) : void 0);
16308
+ if (label) {
16309
+ out.push({
16310
+ type: "text",
16311
+ x: x + barW / 2,
16312
+ y: baseline - bh - 8,
16313
+ text: label,
16314
+ color: "#374151",
16315
+ fontSize: 11,
16316
+ align: "center"
16317
+ });
16318
+ }
16319
+ });
16320
+ pointers.forEach((p) => {
16321
+ if (p.index < 0 || p.index >= bars.length) return;
16322
+ const cx = p.index * slot + slot / 2;
16323
+ const color = p.color ?? DEFAULT_POINTER_COLOR;
16324
+ out.push({
16325
+ type: "arrow",
16326
+ x1: cx,
16327
+ y1: height - 6,
16328
+ x2: cx,
16329
+ y2: baseline + 4,
16330
+ color,
16331
+ lineWidth: 2
16332
+ });
16333
+ if (p.label) {
16334
+ out.push({
16335
+ type: "text",
16336
+ x: cx,
16337
+ y: height - 22,
16338
+ text: p.label,
16339
+ color,
16340
+ fontSize: 11,
16341
+ align: "center"
16342
+ });
16343
+ }
16344
+ });
16345
+ }
16346
+ if (cells.length > 0) {
16347
+ const maxCol = Math.max(0, ...cells.map((c) => c.col)) + 1;
16348
+ const maxRow = Math.max(0, ...cells.map((c) => c.row)) + 1;
16349
+ const cw = width / maxCol;
16350
+ const ch = height / maxRow;
16351
+ cells.forEach((c, i) => {
16352
+ const x = c.col * cw;
16353
+ const y = c.row * ch;
16354
+ const color = c.color ?? DEFAULT_CELL_COLOR;
16355
+ out.push({
16356
+ type: "rect",
16357
+ id: `cell-${i}`,
16358
+ x: x + 1,
16359
+ y: y + 1,
16360
+ width: cw - 2,
16361
+ height: ch - 2,
16362
+ color: "#9ca3af",
16363
+ fill: color
16364
+ });
16365
+ const label = c.label ?? (c.value != null ? String(c.value) : void 0);
16366
+ if (label && cw >= 18 && ch >= 14) {
16367
+ out.push({
16368
+ type: "text",
16369
+ x: x + cw / 2,
16370
+ y: y + ch / 2,
16371
+ text: label,
16372
+ color: "#111827",
16373
+ fontSize: 12,
16374
+ align: "center"
16375
+ });
16376
+ }
16377
+ });
16378
+ }
16379
+ out.push(...shapes);
16380
+ return out;
16381
+ }, [bars, cells, pointers, shapes, width, height]);
16382
+ return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
16383
+ title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
16384
+ /* @__PURE__ */ jsx(
16385
+ LearningCanvas,
16386
+ {
16387
+ width,
16388
+ height,
16389
+ backgroundColor,
16390
+ shapes: derivedShapes,
16391
+ interactive,
16392
+ animate,
16393
+ onShapeClick,
16394
+ isLoading,
16395
+ error
16396
+ }
16397
+ )
16398
+ ] }) });
16399
+ };
16400
+ }
16401
+ });
16160
16402
  var AuthLayout;
16161
16403
  var init_AuthLayout = __esm({
16162
16404
  "components/marketing/templates/AuthLayout.tsx"() {
@@ -45515,6 +45757,7 @@ var init_component_registry_generated = __esm({
45515
45757
  init_ActionTile();
45516
45758
  init_ActivationBlock();
45517
45759
  init_ComponentPatterns();
45760
+ init_AlgorithmCanvas();
45518
45761
  init_AnimatedCounter();
45519
45762
  init_AnimatedGraphic();
45520
45763
  init_AnimatedReveal();
@@ -45813,6 +46056,7 @@ var init_component_registry_generated = __esm({
45813
46056
  "ActivationBlock": ActivationBlock,
45814
46057
  "Alert": AlertPattern,
45815
46058
  "AlertPattern": AlertPattern,
46059
+ "AlgorithmCanvas": AlgorithmCanvas,
45816
46060
  "AnimatedCounter": AnimatedCounter,
45817
46061
  "AnimatedGraphic": AnimatedGraphic,
45818
46062
  "AnimatedReveal": AnimatedReveal,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.94.1",
3
+ "version": "5.95.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -123,7 +123,7 @@
123
123
  "lint": "eslint --no-warn-ignored --max-warnings 0 ."
124
124
  },
125
125
  "dependencies": {
126
- "@almadar/core": "^10.13.0",
126
+ "@almadar/core": "^10.14.0",
127
127
  "@almadar/evaluator": ">=2.9.2",
128
128
  "@almadar/logger": "^1.3.0",
129
129
  "@almadar/patterns": ">=2.35.0",