@superblocksteam/library 2.0.132 → 2.0.133-next.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.
package/dist/lib/index.js CHANGED
@@ -4493,6 +4493,38 @@ function EditorHotkeys({ children }) {
4493
4493
  //#region src/edit-mode/screenshot-handler.ts
4494
4494
  let cleanupCallback$1 = void 0;
4495
4495
  const MAX_SCREENSHOT_DIMENSION = 2e3 * .98;
4496
+ const SCREENSHOT_WEBP_QUALITY = .8;
4497
+ const MAX_SCREENSHOT_BYTES = 256 * 1024;
4498
+ /** Decreasing webp qualities tried, in order, to fit {@link MAX_SCREENSHOT_BYTES}. */
4499
+ const WEBP_QUALITY_LADDER = [
4500
+ .6,
4501
+ .45,
4502
+ .3
4503
+ ];
4504
+ function dataUrlByteLength(dataUrl) {
4505
+ const commaIndex = dataUrl.indexOf(",");
4506
+ const base64 = commaIndex >= 0 ? dataUrl.slice(commaIndex + 1) : dataUrl;
4507
+ if (base64.length === 0) return 0;
4508
+ const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
4509
+ return Math.floor(base64.length * 3 / 4) - padding;
4510
+ }
4511
+ async function enforceByteBudget(dataUrl, reencode, options) {
4512
+ const maxBytes = options?.maxBytes ?? 262144;
4513
+ const qualityLadder = options?.qualityLadder ?? WEBP_QUALITY_LADDER;
4514
+ let best = dataUrl;
4515
+ let bestBytes = dataUrlByteLength(best);
4516
+ if (bestBytes <= maxBytes) return best;
4517
+ for (const quality of qualityLadder) {
4518
+ const candidate = await reencode(quality);
4519
+ const candidateBytes = dataUrlByteLength(candidate);
4520
+ if (candidateBytes < bestBytes) {
4521
+ best = candidate;
4522
+ bestBytes = candidateBytes;
4523
+ }
4524
+ if (bestBytes <= maxBytes) break;
4525
+ }
4526
+ return best;
4527
+ }
4496
4528
  /**
4497
4529
  * Calculate the scale factor for screenshot capture to keep the output image's
4498
4530
  * longest edge under Anthropic's many-image per-image limit (2000px).
@@ -4531,25 +4563,45 @@ function loadImage(dataUrl) {
4531
4563
  });
4532
4564
  }
4533
4565
  /**
4534
- * Downscale a data-URL image so that neither dimension exceeds
4535
- * MAX_SCREENSHOT_DIMENSION. Returns the original if already within limits.
4566
+ * Re-encode a data-URL image to webp via a canvas, optionally rescaling.
4567
+ * `scale` defaults to 1 (recompress at the same dimensions).
4536
4568
  */
4537
- async function ensureWithinDimensionLimit(dataUrl) {
4569
+ async function reencodeWebp(dataUrl, { quality, scale = 1 }) {
4538
4570
  const img = await loadImage(dataUrl);
4539
- const { naturalWidth: width, naturalHeight: height } = img;
4540
- const maxDim = Math.max(width, height);
4541
- if (maxDim <= MAX_SCREENSHOT_DIMENSION) return dataUrl;
4542
- console.warn(`[Library Screenshot Handler] Output image ${width}x${height} exceeds ${MAX_SCREENSHOT_DIMENSION}px limit, resizing…`);
4543
- const scale = MAX_SCREENSHOT_DIMENSION / maxDim;
4544
- const targetWidth = Math.round(width * scale);
4545
- const targetHeight = Math.round(height * scale);
4571
+ const targetWidth = Math.max(1, Math.round(img.naturalWidth * scale));
4572
+ const targetHeight = Math.max(1, Math.round(img.naturalHeight * scale));
4546
4573
  const canvas = document.createElement("canvas");
4547
4574
  canvas.width = targetWidth;
4548
4575
  canvas.height = targetHeight;
4549
4576
  const ctx = canvas.getContext("2d");
4550
4577
  if (!ctx) throw new Error("Canvas 2d context not available");
4551
4578
  ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
4552
- return canvas.toDataURL("image/webp", .85);
4579
+ return canvas.toDataURL("image/webp", quality);
4580
+ }
4581
+ /**
4582
+ * Enforce the model's hard limits on a captured screenshot: first the pixel
4583
+ * dimension cap (see {@link MAX_SCREENSHOT_DIMENSION}), then the byte budget
4584
+ * (oversized payloads stall the plan-generation stream). Returns the original
4585
+ * when it already fits both.
4586
+ */
4587
+ async function ensureWithinLimits(dataUrl) {
4588
+ const { naturalWidth: width, naturalHeight: height } = await loadImage(dataUrl);
4589
+ const maxDim = Math.max(width, height);
4590
+ let result = dataUrl;
4591
+ if (maxDim > MAX_SCREENSHOT_DIMENSION) {
4592
+ console.warn(`[Library Screenshot Handler] Output image ${width}x${height} exceeds ${MAX_SCREENSHOT_DIMENSION}px limit, resizing…`);
4593
+ result = await reencodeWebp(dataUrl, {
4594
+ quality: SCREENSHOT_WEBP_QUALITY,
4595
+ scale: MAX_SCREENSHOT_DIMENSION / maxDim
4596
+ });
4597
+ }
4598
+ const dimensionCapped = result;
4599
+ const beforeBytes = dataUrlByteLength(dimensionCapped);
4600
+ result = await enforceByteBudget(dimensionCapped, (quality) => reencodeWebp(dimensionCapped, { quality }));
4601
+ const afterBytes = dataUrlByteLength(result);
4602
+ if (afterBytes < beforeBytes) console.warn(`[Library Screenshot Handler] Recompressed screenshot ${(beforeBytes / 1024).toFixed(0)}KB -> ${(afterBytes / 1024).toFixed(0)}KB to fit ${(MAX_SCREENSHOT_BYTES / 1024).toFixed(0)}KB budget`);
4603
+ if (afterBytes > 262144) console.warn(`[Library Screenshot Handler] Could not bring screenshot under ${(MAX_SCREENSHOT_BYTES / 1024).toFixed(0)}KB budget; sending ${(afterBytes / 1024).toFixed(0)}KB`);
4604
+ return result;
4553
4605
  }
4554
4606
  /**
4555
4607
  * Counts loading indicators in the DOM that signal data is still being
@@ -4643,6 +4695,7 @@ function initializeScreenshotHandler() {
4643
4695
  const dataUrl = await domToWebp(targetElement, {
4644
4696
  backgroundColor: "#ffffff",
4645
4697
  scale,
4698
+ quality: SCREENSHOT_WEBP_QUALITY,
4646
4699
  ...selector && { onCloneNode: (cloned) => {
4647
4700
  if (cloned instanceof HTMLElement) {
4648
4701
  const computed = getComputedStyle(targetElement);
@@ -4654,8 +4707,8 @@ function initializeScreenshotHandler() {
4654
4707
  } }
4655
4708
  });
4656
4709
  const captureMs = performance.now() - captureStartTime;
4657
- console.log(`${LOG_PREFIX} domToWebp completed in ${captureMs.toFixed(1)}ms, output size: ${(dataUrl.length / 1024).toFixed(1)}KB`);
4658
- const safeDataUrl = await ensureWithinDimensionLimit(dataUrl);
4710
+ console.log(`${LOG_PREFIX} domToWebp completed in ${captureMs.toFixed(1)}ms, output size: ${(dataUrlByteLength(dataUrl) / 1024).toFixed(1)}KB`);
4711
+ const safeDataUrl = await ensureWithinLimits(dataUrl);
4659
4712
  const totalMs = performance.now() - handlerStartTime;
4660
4713
  console.log(`${LOG_PREFIX} Screenshot captured successfully! Total: ${totalMs.toFixed(1)}ms (import: ${importMs.toFixed(1)}ms, capture: ${captureMs.toFixed(1)}ms)`);
4661
4714
  editorBridge.sendCaptureScreenshotResponse(callbackId, safeDataUrl);