pbakaus/impeccable · info

[impeccable] Svelte ancestor crop capture failed, falling ba

Error message

[impeccable] Svelte ancestor crop capture failed, falling back to element capture:

What it means

When an element is captured via an ancestor-crop shader proxy, live-browser first renders the ancestor with modern-screenshot and crops out the element (inside hideCaptureChromeForShaderProxy). If that ancestor render throws — canvas size limits, tainted cross-origin content, renderer unsupported styles — the error is logged as 'ancestor crop capture failed, falling back to element capture:' and a direct capture of the element itself is used instead, so the generate flow continues.

Source

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

      if (pos === 'static') {
        savedPosition = el.style.position;
        el.style.position = 'relative';
      }
      annotNode = buildAnnotationsForCapture(rect, snapshot);
      el.appendChild(annotNode);
    }
    try {
      const ms = await loadModernScreenshot();
      const fontCssText = await collectFontCssText();
      const opts = {
        scale: Math.min(window.devicePixelRatio || 1, 2),
        font: fontCssText ? { cssText: fontCssText } : undefined,
      };
      if (shouldUseAncestorCropShaderProxy(el)) {
        try {
          return await hideCaptureChromeForShaderProxy(() => captureElementFromRenderedAncestor(ms, el, opts));
        } catch (err) {
          console.warn('[impeccable] Svelte ancestor crop capture failed, falling back to element capture:', err);
        }
      }
      const bg = resolveCanvasBackground(el);
      // Fast path: the element paints its own background, or an opaque ancestor
      // color was found. modern-screenshot bakes that color; paper matches it.
      if (bg !== '#ffffff') {
        const blob = await ms.domToBlob(el, { ...opts, ...(bg ? { backgroundColor: bg } : {}) });
        return { blob, paper: bg ? cssColorToRgb01(bg) : resolvePaperRgb(el) };
      }
      // Transparent up to the root. The visible backdrop may still come from an
      // ancestor's background-image or a covering positioned layer (e.g. a hero
      // art div) that the color walk can't see. Capture that ancestor and crop
      // to the element so the real backdrop is embedded - correct for both the
      // shader and the screenshot sent to the model. Fall back to white only
      // when nothing is actually painted behind the element.
      const backdrop = findBackdropAncestor(el);
      if (!backdrop) {
        const blob = await ms.domToBlob(el, { ...opts, backgroundColor: '#ffffff' });

View on GitHub (pinned to f88b2837a7)

Solutions

  1. No action usually needed — the element-level fallback capture is taken automatically
  2. If the fallback's background/paper looks wrong, capture from a plainer ancestor or fix cross-origin CORS headers on images/fonts
  3. Reduce window scale (device pixel ratio cap is already 2) for gigantic ancestors
Defensive patterns

Strategy: fallback

Validate before calling

// Cap the ancestor render size before attempting crop capture
const MAX = 4096;
const scale = Math.min(window.devicePixelRatio || 1, 2, MAX / Math.max(ancestorRect.width, ancestorRect.height));

Try / catch

try { return await captureElementFromRenderedAncestor(ms, el, opts); } catch (err) { console.warn(err); /* fall through to direct element capture */ }

Prevention

When it happens

Trigger: The proxy ancestor is enormous (viewport-sized hero at DPR 2 exceeding max canvas/texture size); ancestor contains cross-origin images or fonts that taint the canvas; modern-screenshot hits an unimplemented CSS feature inside the ancestor.

Common situations: Capturing an element inside a full-bleed hero with video/background-image art; very high pixel-ratio displays; pages pulling cross-origin assets without CORS headers.

Related errors


AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18). Data as JSON: /api/errors/51a0ea397bf4ea95. Report an issue: GitHub.