title and color can be embedded a hundred times with a hundred different values without duplicating any HTML.
Declaring Variables
Adddata-composition-variables to the <html> root of any composition. Its value is a JSON array of variable declarations — one object per variable:
compositions/card.html
id, type, label, and default. id must be unique within the composition.
Variable Types
| Type | default value | Extra options |
|---|---|---|
string | "some text" | placeholder?: string, maxLength?: number |
number | 0 | min?: number, max?: number, step?: number, unit?: string |
color | "#rrggbb" | — |
boolean | true / false | — |
enum | one of the option values | options: [{value: string, label: string}] |
label, type, and the type-specific options to render the right input widget for each variable.
What can be a variable
Variables come in two layers. The five declared types above cover typed primitive data — strings, numbers, colors, booleans, enums. For everything else, astring variable holding a URL is the escape hatch: your composition reads the URL and assigns it to whatever DOM element needs it.
Parameterizing media assets
The same composition can render different images, video clips, or audio tracks just by swapping URLs through a string variable:compositions/product-card.html
The runtime probes the DOM after your composition script runs, so a
<video> or <audio> src assigned at runtime from a variable is discovered and pre-extracted for the render. No extra wiring required — just set the src from your variable.<img src>— assign from a string variable. Chrome fetches it during capture like any other image; no extra config.<video src>— assign from a string variable, but keep the timing attributes (data-start,data-duration,data-track-index,data-has-audio) on the element itself. The probe phase scansvideo[data-start]elements after your script runs and reads the resolvedsrcfor pre-extraction.<audio src>— same as video. The audio is decoded during capture and mixed into the final output.
Swapping media: do you need to vary duration too?
A common follow-up: if a variable swaps a<video> to a different clip, does data-duration need to change too? Usually no. data-duration is optional on <video> and <audio> — leave it off and the renderer ffprobes the source and uses its natural length:
compositions/hero.html
number variable and apply it via the same script:
compositions/hero.html
data-duration from the live DOM after your script runs, so an attribute written programmatically behaves identically to one baked into the source HTML.
What can’t be a variable
A small set of inputs are read once from the source HTML or from the CLI / SDK, with no live-DOM re-read — no script (and therefore no variable) can change them:| What | Mechanism (not a variable) |
|---|---|
| Composition dimensions | data-width / data-height on the composition element — parsed from the source HTML at compile time, not from the live DOM |
| Frame rate | --fps flag on hyperframes render, or config.fps in the SDK |
| Output format / codec / quality | --format / --codec / --quality flags, or the SDK equivalents |
| A sibling or parent composition’s variables | Variables are per-composition; use data-variable-values on each sub-comp host element to pass overrides |
src, even clip data-duration as shown above. They can’t change inputs the renderer reads once at compile time (dimensions) or that live entirely outside the composition (CLI flags, encoder settings).
Reading Variables at Runtime
Inside any composition script, callwindow.__hyperframes.getVariables() to get the resolved variable values. The return type is Partial<Record<string, unknown>> — use destructuring with defaults matching the declared default values:
compositions/card.html
__hyperframes.getVariables() is a shorthand for window.__hyperframes.getVariables() and works in both top-level and sub-composition scripts. The runtime automatically scopes sub-compositions so each instance sees its own resolved values.
Per-instance Overrides (Sub-compositions)
When embedding a composition inside another, usedata-variable-values on the host element to pass a JSON object of override values for that particular instance:
index.html
card.html source, but each instance receives different values. The runtime merges the host’s data-variable-values over the sub-comp’s declared defaults on a per-instance basis — the same sub-composition can run with completely different content simultaneously.
CLI Overrides (Top-level Renders)
Pass variable values at render time with--variables or --variables-file. These override the declared defaults for the top-level composition:
Terminal
--strict-variables turns variable warnings into errors. Any variable in --variables that is not declared in data-composition-variables, or whose value does not match the declared type, causes the render to exit non-zero. Useful in CI pipelines where an undeclared variable key likely indicates a typo or a schema mismatch.
CLI overrides apply only to the top-level composition. Sub-composition variables are controlled by
data-variable-values on each host element.Layering and Precedence
Variable values are resolved by merging three sources, lowest to highest precedence:| Source | Precedence | Where declared |
|---|---|---|
| Declared defaults | Lowest | data-composition-variables on <html> |
| Per-instance host overrides | Middle | data-variable-values on the sub-comp host element |
CLI --variables flag | Highest | hyperframes render --variables '{...}' |
default is used.
Validation
The linter checks variable declarations statically:Terminal
id, type, label, default), and type mismatches between type and the default value. Fix lint errors before rendering — they indicate the runtime will be unable to resolve variables correctly.
At render time, the CLI validates --variables against the schema and reports issues as warnings (or errors with --strict-variables):
- undeclared — a key in
--variableshas no matchingidindata-composition-variables - type-mismatch — the value’s JavaScript type does not match the declared
type(e.g. a string where a number is expected) - enum-out-of-range — an enum value is not in the declared
optionslist
Inspecting Variables Programmatically
If you are building tooling on top of@hyperframes/core, the variable declarations are readable without rendering:
Next Steps
Data Attributes
Full reference for data-composition-variables and data-variable-values attributes
Compositions
How nested compositions use variables for reuse
Rendering
CLI flags for passing variables at render time
CLI Reference
All CLI commands and flags