pbakaus/impeccable · error · Error

Selected element has no visible capture rect

Error message

Selected element has no visible capture rect

What it means

After computing the element's rect relative to the captured ancestor canvas, this is thrown when the scaled crop width or height is <= 0 — i.e. the selected element has no visible box to crop from the rendered canvas. The capture pipeline refuses to produce a zero-area canvas.

Source

Thrown at skill/scripts/live-browser.js:8148

  // Capture the element (with current annotations baked in) and return
  // { blob, paper }: the PNG Blob, plus the representative backdrop tone for the
  // shader's halftone ground (so capture, upload, and shader all agree on what
  // sits behind the element). Shared between the Go flow (uploads the blob) and
  // the shader-resume path.
  async function captureElementFromRenderedAncestor(ms, el, opts) {
    const doc = el.ownerDocument || document;
    const captureRoot = findShaderProxyCaptureRoot(el);
    if (!captureRoot) throw new Error('No painted ancestor for Svelte shader proxy');
    const rootCanvas = await ms.domToCanvas(captureRoot, opts);
    const S = opts.scale;
    const er = el.getBoundingClientRect();
    const rr = captureRoot.getBoundingClientRect();
    const sx = (er.left - rr.left) * S;
    const sy = (er.top - rr.top) * S;
    const sw = er.width * S;
    const sh = er.height * S;
    if (sw <= 0 || sh <= 0) throw new Error('Selected element has no visible capture rect');
    const crop = doc.createElement('canvas');
    crop.width = Math.max(1, Math.round(sw));
    crop.height = Math.max(1, Math.round(sh));
    const cctx = crop.getContext('2d', { willReadFrequently: true });
    cctx.drawImage(rootCanvas, sx, sy, sw, sh, 0, 0, crop.width, crop.height);
    const paper = dominantRgb01(cctx, crop.width, crop.height) || averageRgb01(cctx, crop.width, crop.height);
    const blob = await new Promise((res) => crop.toBlob(res, 'image/png'));
    if (!blob) throw new Error('Ancestor crop failed to produce a PNG blob');
    return { blob, paper };
  }

  async function captureElementToBlob(el, snapshot, rect) {
    try { if (document.fonts?.ready) await document.fonts.ready; } catch {}
    const hasAnnotations = snapshot && (snapshot.comments.length > 0 || snapshot.strokes.length > 0);
    let annotNode = null;
    let savedPosition = null;
    if (hasAnnotations) {
      const pos = getComputedStyle(el).position;

View on GitHub (pinned to 2bc2879276)

Solutions

  1. Verify the element is visible and has non-zero bounding box before triggering capture (check getBoundingClientRect yourself)
  2. Re-select the actual visible element rather than a hidden wrapper
  3. Ensure any collapse/animation has finished and the element is painted before capturing
  4. If capturing programmatically, force layout/visibility (or skip the effect) when rect is empty

Example fix

// before
const crop = captureElementFromRenderedAncestor(ms, el, opts); // throws deep inside
// after
const r = el.getBoundingClientRect();
if (r.width <= 0 || r.height <= 0) throw new Error('Element is not visible; nothing to capture');
const crop = captureElementFromRenderedAncestor(ms, el, opts);
Defensive patterns

Strategy: validation

Validate before calling

const r = el.getBoundingClientRect();
if (r.width <= 0 || r.height <= 0) {
  throw new Error('Element has no visible capture rect');
}

Type guard

function hasVisibleRect(el) {
  const r = el.getBoundingClientRect();
  return r.width > 0 && r.height > 0;
}

Try / catch

try {
  await captureElementToBlob(el, snapshot, rect);
} catch (err) {
  if (err.message.includes('no visible capture rect')) {
    showToast('Selected element is not visible; make it visible before applying the effect.');
  }
}

Prevention

When it happens

Trigger: el.getBoundingClientRect() returns zero width/height because the element is display:none, not rendered, detached from the document, or collapsed (e.g. empty flex item with no size).

Common situations: Selecting an element in DevTools-like UI while it is hidden behind a toggle; targeting a slot/placeholder with no rendered content; capture triggered before first paint after route change.

Related errors


AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08). Data as JSON: /api/errors/3314392a74170847. Report an issue: GitHub.