heygen-com/hyperframes · error · Error

--shot: --selector '${scopeSelector}' matched no element.

Error message

--shot: --selector '${scopeSelector}' matched no element.

What it means

Thrown by resolveScopedRequests when the --shot --selector <scope> value did not match any element in the live DOM (resolveScopeInBrowser reported scopeExists === false). The scope selector is used to narrow which animated elements to sample; if it matches nothing, the shot cannot proceed.

Source

Thrown at packages/cli/src/commands/motionShot.ts:445

  return { selectors, scopeExists: probe.scopeExists };
}

// --selector scope: the focused element is often a STATIC wrapper (`.clip`)
// whose animated children carry the tweens. Resolve, in the live DOM, to the
// scope itself if it animates, else its animated descendants — so the shot
// works on the standard composition shape instead of erroring.
async function resolveScopedRequests(
  page: import("puppeteer-core").Page,
  requests: ShotRequest[],
  scopeSelector: string,
): Promise<ShotRequest[]> {
  const resolved = await resolveScopeInBrowser(
    page,
    scopeSelector,
    requests.map((r) => r.selector),
  );
  if (!resolved.scopeExists) {
    throw new Error(`--shot: --selector '${scopeSelector}' matched no element.`);
  }
  if (resolved.selectors.length === 0) {
    const nearest = requests
      .slice(0, 5)
      .map((r) => r.selector)
      .join(", ");
    throw new Error(
      `--shot: nothing animates under '${scopeSelector}'. Nearest animated elements: ${nearest || "(none)"}.`,
    );
  }
  return resolved.selectors.map((selector) => ({ selector }));
}

// In-tick capture: seek the timeline (fires the composition's onUpdate render
// synchronously via the shared window.__hfSeekAllAdapters) + nudge the
// three-adapter, then drawImage every <canvas> onto an offscreen canvas in the
// SAME tick — before the browser clears the GL drawing buffer (works without
// preserveDrawingBuffer; page.screenshot can't see the GL buffer here).

View on GitHub (pinned to c2996c8626)

Solutions

  1. Verify the selector exists in the composition HTML
  2. Use a broader or corrected selector that matches a real element
  3. Drop --selector to sample all animated elements globally
  4. Check that the element is present after bundling (not stripped by the build)

Example fix

// before
hyperframes shot --selector '.nonexistent' out.png
// after — use a selector that matches
hyperframes shot --selector '#hero' out.png
Defensive patterns

Strategy: validation

Validate before calling

// Validate the selector matches before running the shot:
import { parseHTML } from 'linkedom';
const doc = parseHTML(html).document;
if (!doc.querySelector(scopeSelector)) {
  throw new Error(`Selector '${scopeSelector}' matches nothing in the composition`);
}

Prevention

When it happens

Trigger: Running `hyperframes shot --selector '.nonexistent' out.png` or using an ID that doesn't exist in the bundled composition. The selector is evaluated in the live browser DOM after bundling, so dynamically-removed elements also trigger this.

Common situations: Typos in selectors. Selectors that exist in source but are stripped during bundling. IDs or classes renamed during refactoring without updating the shot command. Selectors targeting elements added by JS that hasn't executed.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/1606ea430c8bb83b. Report an issue: GitHub.