How Hyperframes Detects Non‑Deterministic JavaScript Code: A Deep Dive into Static Analysis

Hyperframes detects non‑deterministic JavaScript by statically lint‑checking every inline <script> block for prohibited patterns like Math.random() and Date.now() before rendering, ensuring deterministic video generation without executing the code.

The heygen-com/hyperframes framework guarantees that video renders are pixel‑perfect and reproducible by eliminating sources of runtime variability at the source code level. Rather than executing user scripts to observe behavior, the framework employs a static analysis pipeline that scans inline JavaScript for time‑based and randomness APIs. This article explains how the hyperframes lint command implements this detection through the core rule set.

The Linting Pipeline: From HTML to Findings

The detection process begins when the CLI parses an HTML composition and extracts all inline <script> blocks. External scripts with src attributes are intentionally ignored, as their content cannot be statically verified. Each script’s raw text is stored in the scripts array of the LintContext, defined in packages/core/src/context.ts and accessed by the rule set in packages/core/src/lint/rules/core.ts (lines 74‑80).

Normalizing Code by Stripping Comments

Before pattern matching, the linter normalizes each script by removing single‑line and block comments. This prevents false positives where prohibited API names appear inside documentation rather than executable code. The implementation uses two regular expressions applied sequentially in core.ts lines 306‑308:

const stripped = script.content
    .replace(/\/\/.*$/gm, "")
    .replace(/\/\*[\s\S]*?\*\//g, "");

Pattern Matching Against Non‑Deterministic APIs

With comments removed, the linter checks the stripped content against a hard‑coded array of regular expressions defined in core.ts lines 777‑803. The current prohibited patterns include:

  • /Math\.random\s*\(/ – Flags Math.random() calls
  • /Date\.now\s*\(/ – Flags Date.now() calls
  • /new\s+Date\s*\(/ – Flags new Date() constructor calls
  • /performance\.now\s*\(/ – Flags performance.now() calls
  • /crypto\.getRandomValues\s*\(/ – Flags crypto.getRandomValues() calls

Each pattern includes a descriptive label and a specific fix hint, such as recommending a seeded PRNG like mulberry32 to replace Math.random().

Core Implementation: The non_deterministic_code Rule

The actual detection logic resides in the non_deterministic_code rule within the exported coreRules array. For each script in the LintContext, the rule iterates over the pattern list and tests the stripped content (lines 311‑319). When a match is found, the rule generates a finding with:

  • Code: non_deterministic_code
  • Severity: error
  • Message: Description of the prohibited API detected
  • Hint: Actionable guidance (e.g., "Use a seeded PRNG")
  • Snippet: Context from the offending script

This approach guarantees that non‑deterministic code is caught without executing the user script, eliminating the possibility of runtime side effects during analysis.

Running the Linter in Practice

To verify a composition before rendering, run the CLI command:

npx hyperframes lint my-composition.html

Consider the following HTML that would trigger violations:

<script>
  const seed = Math.random();   // ❌ non‑deterministic
  const now = Date.now();       // ❌ non‑deterministic
</script>

The linter produces output similar to:


✖ non_deterministic_code (error)
  Script contains `Math.random()` which produces non‑deterministic output.
  Hint: Use a seeded PRNG (e.g. a simple mulberry32) so renders are deterministic.

Developers must replace these APIs with deterministic alternatives—such as using GSAP timeline positions instead of Date.now()—before the composition can be safely rendered.

Key Files and Architecture

The static analysis pipeline spans several packages:

Summary

  • Hyperframes uses static analysis, not execution, to detect non‑deterministic JavaScript.
  • The linter extracts inline scripts, strips comments, and matches against regex patterns for APIs like Math.random() and Date.now().
  • Violations are reported with specific error codes, severity levels, and fix hints before rendering begins.
  • The core logic lives in packages/core/src/lint/rules/core.ts within the coreRules array.
  • Developers must use deterministic alternatives such as seeded PRNGs or timeline‑based positioning to pass validation.

Frequently Asked Questions

Does Hyperframes execute my JavaScript to detect non‑deterministic code?

No. Hyperframes performs static linting only. The hyperframes lint command parses your HTML composition and scans the raw text of inline <script> blocks using regular expressions. It never evaluates or runs the JavaScript, ensuring no side effects occur during analysis.

What specific JavaScript APIs does Hyperframes flag as non‑deterministic?

According to the source code in packages/core/src/lint/rules/core.ts (lines 777‑803), the linter flags Math.random(), Date.now(), new Date(), performance.now(), and crypto.getRandomValues(). Each of these APIs introduces variability based on system time or hardware randomness, which breaks deterministic video rendering.

How do I fix non‑deterministic code errors in Hyperframes?

Replace flagged APIs with deterministic alternatives. For Math.random(), implement a seeded PRNG such as mulberry32. For Date.now() or new Date(), use GSAP timeline positions or other frame‑based timing references. The linter provides specific hints for each violation type to guide the replacement.

Does Hyperframes check external script files?

No. The linter specifically ignores external scripts referenced via <script src="..."> attributes and only analyzes inline scripts within the HTML composition. This limitation is noted in the LintContext implementation where only inline script content is extracted into the scripts array.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →