How the Variable Validation System Works in Hyperframes Runtime

The Hyperframes runtime validates composition variables through a deterministic schema-based check that ensures type safety, required field presence, and enum constraints before rendering.

The heygen-com/hyperframes repository implements a strict variable validation system to prevent runtime errors in dynamic compositions. When a composition loads, the runtime executes the validation helper to compare supplied values against a declared schema extracted from the composition's metadata. This process ensures that rendering pipelines receive only well-typed, expected data, eliminating crashes caused by type mismatches or missing required fields.

Schema Declaration and Variable Types

Variables in Hyperframes are declared using a <script type="application/hyperframes-variables"> block within the composition HTML or via a standalone JSON configuration file. The schema defines each variable's type, whether it is required, allowed enum values, and optional default values. The parser in packages/core/src/parsers/htmlParser.ts extracts these declarations into a VariableDeclarationMap that serves as the validation contract.

Supported types include:

  • string: Plain text values
  • number: Numeric values rejecting NaN and Infinity
  • boolean: Boolean values or string coercion of "true" and "false"
  • enum: Values constrained to a specific set of allowed literals
  • custom formats: Built-in patterns such as hex color strings

The Validation Pipeline

The core validation logic resides in packages/core/src/runtime/validateVariables.ts. The validateVariables function accepts a Record<string, unknown> of user-supplied values and a VariableDeclarationMap, returning an array of VariableValidationIssue objects.

Required Field Verification

The validator first iterates through the declaration map to identify missing required variables. If a required key is absent from the supplied data, the system pushes an issue with type "missing" containing the variable name.

Type-Specific Validation

For each supplied variable, the system performs strict type checking according to the schema definition:

  • String validation: Verifies typeof value === "string"
  • Number validation: Confirms typeof value === "number" and explicitly rejects NaN or Infinity
  • Boolean coercion: Accepts native booleans or the exact strings "true" and "false"; other values generate an "invalid-boolean" issue
  • Enum constraints: Validates that the value exists within the declared decl.values array; mismatches produce "invalid-enum-value" issues listing the allowed options
  • Format validation: Applies regex patterns for declared formats, flagging failures as "invalid-format" issues

Extra Field Detection

Any key present in the user-supplied object but missing from the declaration map is flagged as an "extra-field" issue. This strict matching prevents typos and undefined behavior in compositions.

Core Implementation

The following implementation from packages/core/src/runtime/validateVariables.ts illustrates the validation logic:

export function validateVariables(
  vars: Record<string, unknown>,
  decls: VariableDeclarationMap,
): VariableValidationIssue[] {
  const issues: VariableValidationIssue[] = [];

  // Check required variables
  for (const [name, decl] of Object.entries(decls)) {
    if (decl.required && !(name in vars)) {
      issues.push({ type: "missing", name });
    }
  }

  // Validate each supplied variable
  for (const [name, value] of Object.entries(vars)) {
    const decl = decls[name];
    if (!decl) {
      issues.push({ type: "extra-field", name });
      continue;
    }

    // Type-specific checks
    switch (decl.type) {
      case "string":
        if (typeof value !== "string") {
          issues.push({ type: "type-mismatch", name, expected: "string" });
        }
        break;

      case "number":
        if (typeof value !== "number" || Number.isNaN(value)) {
          issues.push({ type: "invalid-number", name });
        }
        break;

      case "boolean":
        if (typeof value !== "boolean" && !(value === "true" || value === "false")) {
          issues.push({ type: "invalid-boolean", name });
        }
        break;

      case "enum":
        if (!decl.values?.includes(value as string)) {
          issues.push({ type: "invalid-enum-value", name, allowed: decl.values! });
        }
        break;

      // Add more custom format checks here
    }
  }

  return issues;
}

Test Suite Examples

The test file packages/core/src/runtime/validateVariables.test.ts demonstrates expected behavior:

const DECLS = {
  title: { type: "string", required: true },
  count: { type: "number" },
  active: { type: "boolean" },
  theme: { type: "enum", values: ["midnight", "sunrise"] },
};

// Valid case
expect(validateVariables({ title: "Demo" }, DECLS)).toEqual([]);

// Missing required
expect(validateVariables({ }, DECLS)).toEqual([{type:"missing",name:"title"}]);

// Type mismatch
expect(validateVariables({ count: "three" }, DECLS)).toEqual([
  {type:"type-mismatch",name:"count",expected:"number"}
]);

// Invalid enum
expect(validateVariables({ theme: "neon" }, DECLS)).toEqual([
  {type:"invalid-enum-value",name:"theme",allowed:["midnight","sunrise"]}
]);

CLI and Programmatic Usage

Command-Line Interface

When using the Hyperframes CLI, developers pass variables via --var flags:

hyperframes render my-composition.html \
  --var title="My Video" \
  --var count=5 \
  --var active=true \
  --var theme=midnight

The CLI implementation in packages/cli/src/commands/render.ts parses these flags into an object and invokes validateVariables before executing the render pipeline.

Programmatic Integration

Custom plugins can import the validator directly:

import { validateVariables } from "hyperframes/core/runtime";

export function myPlugin(context) {
  const vars = context.getCompositionVariables();
  const schema = context.getVariableSchema();

  const problems = validateVariables(vars, schema);
  if (problems.length) {
    throw new Error(`Invalid variables: ${problems.map(i => i.name).join(", ")}`);
  }

  // Variables validated - safe to proceed with rendering
}

Summary

  • The variable validation system in Hyperframes runtime enforces type safety through a declarative schema extracted from composition metadata in packages/core/src/parsers/htmlParser.ts.
  • The validateVariables function in packages/core/src/runtime/validateVariables.ts performs deterministic checks for required fields, type mismatches, enum constraints, and extra fields.
  • The system rejects NaN and Infinity for numeric types and coerces boolean strings while rejecting invalid formats.
  • Validation returns an array of VariableValidationIssue objects; an empty array indicates success and permits rendering to proceed.
  • Both CLI tools and programmatic APIs expose this validation layer to ensure deterministic composition rendering across all execution contexts.

Frequently Asked Questions

What happens if I pass an undefined variable to a Hyperframes composition?

The validator flags undefined values as type mismatches for non-optional fields. If the variable is declared as required in the schema, the system generates a "missing" issue. If the variable is optional but provided as undefined, it typically fails the type check for the declared type, resulting in a type-mismatch error.

Does Hyperframes support custom validation rules beyond the built-in types?

The current implementation supports custom format validation through regex patterns, such as hex color validation. However, complex custom validation logic requires manual implementation outside the validateVariables function. Developers can pre-validate variables programmatically using the exposed API before passing them to the runtime.

How does the runtime handle boolean values passed as strings?

The validation system accepts both native JavaScript booleans and the string literals "true" and "false", coercing them to proper boolean values. Any other string value generates an "invalid-boolean" validation issue, preventing ambiguous truthy or falsy interpretations that could cause rendering inconsistencies.

Where is the variable schema defined in a Hyperframes project?

The schema is declared within a <script type="application/hyperframes-variables"> block inside your composition HTML file, or alternatively via a separate JSON configuration. The parser in packages/core/src/parsers/htmlParser.ts extracts these declarations during the loading phase to create the VariableDeclarationMap used by the validator.

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 →