Skip to content

Compiler tag scanner matches media tags inside comments → phantom auto-start media, comment text corrupted, unnecessary browser probe every render #1938

Description

@wkasekende

Version: hyperframes 0.7.31 · Node 22.15 · Linux (WSL2)

Summary

The timing compiler scans the raw composition text for media tags with regexes that don't exclude comments. A JS/HTML comment that merely mentions <video> or <audio> (e.g. documentation prose) is treated as a real untimed media element: the compiler injects id/data-start="0"/data-hf-auto-start into the comment text, and the render pipeline then launches a browser probe on every render because runProbeStage's check is a substring match over the final HTML (compiled.html.includes("data-hf-auto-start")).

Minimal repro

A composition with no media at all, just a comment that mentions a tag:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=640, height=360" />
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
    <style>
      body { margin: 0; background: #000; }
      #root { position: relative; width: 640px; height: 360px; overflow: hidden; }
      .clip { position: absolute; inset: 0; display: grid; place-items: center; }
      h1 { color: #fff; font-family: sans-serif; }
    </style>
  </head>
  <body>
    <div id="root" data-composition-id="main" data-start="0" data-width="640" data-height="360" data-duration="2">
      <section id="card" class="clip" data-start="0" data-duration="2" data-track-index="1"><h1 id="t">No media here</h1></section>
    </div>
    <script>
      // This composition contains no media at all. But this comment
      // mentions a <video> tag — and that is enough to trigger the bug.
      window.__timelines = window.__timelines || {};
      const tl = gsap.timeline({ paused: true });
      tl.from("#t", { opacity: 0, duration: 0.5 }, 0.2);
      window.__timelines["main"] = tl;
    </script>
  </body>
</html>

npx hyperframes render on this project produces:

  1. The comment is rewritten in the compiled/served page:
    // mentions a <video id="hf-video-0" data-start="0" data-hf-auto-start="" data-has-audio="true"> tag — and that is enough…
    
  2. Compile metadata correctly says videoCount: 0, audioCount: 0 — yet the probe launches anyway, with an empty reasons list (auto-start isn't reported as a reason):
    [INFO] Compiled composition metadata {... "videoCount":0,"audioCount":0 ...}
    [INFO] Launching browser for composition probe... {"reasons":[]}
    

Impact

  • Every render of an affected composition pays an unnecessary browser launch. In our (admittedly hostile) WSL environment the probe session reliably burned the full 45s playerReadyTimeout per render and was also the source of intermittent Network.enable timed out failures — we spent days retrying around a probe that should never have run. Removing the tag syntax from one comment took a 10s-segment draft from 63s to 19s.
  • The composition's comment text is silently corrupted in the served page (confusing when debugging the compiled output).
  • Because the probe's reasons array doesn't include the auto-start condition, the launch looks completely unexplained in logs, which makes this painful to diagnose.

Where it lives (dist/cli.js, 0.7.31)

  • compileTag / injectAttr in ../core/dist/compiler/timingCompiler.js — the tag regex matches inside comments; when the phantom "tag" lacks data-start, data-hf-auto-start is injected.
  • runProbeStage: const hasAutoStartVideos = compiled.html.includes("data-hf-auto-start") — a substring match over the whole document, so any occurrence of that string (mutated comments, or even user text mentioning the attribute) forces needsBrowser.

Suggested fixes

  1. Strip/mask comments (and ideally string literals) before the media-tag scan, or use a real HTML parser for tag discovery.
  2. Track auto-start media as compile metadata (a count/list alongside videoCount) instead of substring-matching the final HTML.
  3. Add the auto-start condition to the probe's reasons array so the launch is at least explainable from logs.

Happy to provide more logs or test a patch.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions