mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
A declared composition variable was written to the composition root as a CSS custom property named after its own id, with no namespace. A variable called accent therefore set --accent inline and shadowed the host theme for that whole subtree. That is worse than a naming clash. The accent enum values are green, blue and violet, which are not colours, they are selectors a composition maps onto theme slots. A representative composition maps blue to var(--accent, #18181b). The runtime then set --accent to blue, so the lookup resolved to the CSS keyword and no host theme could win. green and violet escaped only because they route to --brand and --accent-2, which nothing shadowed, which is why this survived: it was invisible for two of three values. Variables are now written to --hf-var-<slug>. The bare name is still written as a deprecated alias, but only for ids that are not reserved theme tokens, which is what actually fixes the collision. Four writers had the bug, not one: the runtime bindings, the scoped getVariables path, the compiler stylesheet, and the SDK mutate and apply-patches path. Fixing only the runtime left the compiler emitting the bare name into compiled output, where a host theme supplied as an inline style attribute still rendered the keyword. All four now route through one helper, and the helper takes the raw id so callers cannot derive the name themselves. That last point closed a real defect rather than a tidy-up. Two sites derived the property name differently, one verbatim and one slugged, so an id like Accent produced two disjoint property sets: one path reserved it, the other aliased it, and an SDK edit silently never landed. A test pins that every injection path derives one name per id. Docs that taught binding the bare name are corrected, including the capstone, whose ink variable is reserved and would have re-skinned the ground while quietly ignoring the ink. Rendered output is unchanged there, so the published videos stay accurate.
218 lines
6.8 KiB
Plaintext
218 lines
6.8 KiB
Plaintext
---
|
||
title: "Reuse a design with variables"
|
||
sidebarTitle: "Variables"
|
||
description: "Change approved text, colors, media, and choices without rebuilding the composition."
|
||
---
|
||
|
||
Variables expose the parts of a composition that are meant to change. One
|
||
customer card can accept a different name, logo, color, and plan while keeping
|
||
the same layout and motion.
|
||
|
||
Use a variable when the design should remain stable across versions. Make a
|
||
normal source edit when the structure itself needs to change.
|
||
|
||
<div className="not-prose my-7 grid grid-cols-2 gap-3">
|
||
<div className="overflow-hidden rounded-xl border border-zinc-200 bg-zinc-950 dark:border-zinc-800">
|
||
<video
|
||
className="aspect-video w-full object-cover"
|
||
src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/validate-variables-default.mp4#t=0.1"
|
||
autoPlay
|
||
muted
|
||
loop
|
||
playsInline
|
||
preload="metadata"
|
||
/>
|
||
<div className="px-3 py-2 text-sm text-zinc-600 dark:text-zinc-400">Default values</div>
|
||
</div>
|
||
<div className="overflow-hidden rounded-xl border border-zinc-200 bg-zinc-950 dark:border-zinc-800">
|
||
<video
|
||
className="aspect-video w-full object-cover"
|
||
src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/validate-variables-variant.mp4#t=0.1"
|
||
autoPlay
|
||
muted
|
||
loop
|
||
playsInline
|
||
preload="metadata"
|
||
/>
|
||
<div className="px-3 py-2 text-sm text-zinc-600 dark:text-zinc-400">
|
||
The same design with different values
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
## Use variables in Studio
|
||
|
||
Studio can create and bind variables, preview overrides, and copy the reviewed
|
||
values into a render command. Follow [Use variables and templates](/studio/variables)
|
||
for that complete workflow.
|
||
|
||
## Advanced: declare the approved inputs
|
||
|
||
Variables live on the composition declaration:
|
||
|
||
```html compositions/card.html
|
||
<html
|
||
data-composition-variables='[
|
||
{"id":"title","type":"string","label":"Title","default":"Pro"},
|
||
{"id":"accent","type":"color","label":"Accent color","default":"#6c5ce7"},
|
||
{"id":"logo","type":"string","label":"Logo","default":"assets/logo.svg"}
|
||
]'
|
||
></html>
|
||
```
|
||
|
||
Supported declared types are:
|
||
|
||
| Type | Good for |
|
||
| --------- | -------------------------------------- |
|
||
| `string` | Text or a media path |
|
||
| `number` | Counts, positions, sizes, or strengths |
|
||
| `color` | Approved color choices |
|
||
| `boolean` | On or off |
|
||
| `enum` | One value from an approved list |
|
||
| `font` | A font-family choice |
|
||
| `image` | An image path or image value |
|
||
|
||
The type lets Studio show the right control and lets rendering catch invalid
|
||
values.
|
||
|
||
## Bind common values without a script
|
||
|
||
Use direct bindings for the normal cases:
|
||
|
||
```html
|
||
<h1 data-var-text="title">Pro</h1>
|
||
|
||
<img data-var-src="logo" src="assets/logo.svg" alt="" />
|
||
|
||
<style>
|
||
.card-title {
|
||
color: var(--hf-var-accent);
|
||
}
|
||
</style>
|
||
```
|
||
|
||
- `data-var-text` replaces the element’s own text.
|
||
- `data-var-src` replaces an image, video, audio, or source URL.
|
||
- Scalar variables are available as CSS custom properties named
|
||
`--hf-var-<slug>`, so the `accent` variable above is read as
|
||
`var(--hf-var-accent)`.
|
||
|
||
The slug is the id lowercased, with anything that is not a letter, digit or
|
||
hyphen replaced by a hyphen. So `accentColor` is readable as
|
||
`var(--hf-var-accentcolor)`, and `swap_at` as `var(--hf-var-swap-at)`.
|
||
|
||
<Note>
|
||
**How a variable is named in CSS.** Every scalar variable is written to
|
||
`--hf-var-<slug>`. It is also written to the bare `--<slug>`, but only when the id
|
||
is not one of the fifteen reserved theme-token names: `accent`, `accent-2`,
|
||
`accent-3`, `accent2`, `bg`, `border`, `brand`, `fg`, `ink`, `muted`,
|
||
`primary`, `secondary`, `surface`, `tertiary`, `text`. Those names belong to
|
||
the page hosting the composition, so a variable never writes them. A variable
|
||
called `accent` cannot shadow the host theme's `--accent`.
|
||
|
||
The bare `--<slug>` alias is deprecated and will be removed in a future release.
|
||
Bind `var(--hf-var-<slug>)` in new work. When a value should follow the host
|
||
theme if there is one and fall back to the declared variable otherwise, write
|
||
`var(--accent, var(--hf-var-accent))`.
|
||
</Note>
|
||
|
||
Use `window.__hyperframes.getVariables()` only when the result needs conditions,
|
||
loops, or derived values:
|
||
|
||
```js
|
||
const { featured = false } = window.__hyperframes.getVariables();
|
||
document.querySelector(".badge").hidden = !featured;
|
||
```
|
||
|
||
## Give each nested composition different values
|
||
|
||
A parent can reuse the same composition several times:
|
||
|
||
```html index.html
|
||
<div
|
||
data-composition-id="card-pro"
|
||
data-composition-src="compositions/card.html"
|
||
data-start="0"
|
||
data-duration="3"
|
||
data-track-index="1"
|
||
data-variable-values='{"title":"Pro","accent":"#ff4d4f"}'
|
||
></div>
|
||
|
||
<div
|
||
data-composition-id="card-enterprise"
|
||
data-composition-src="compositions/card.html"
|
||
data-start="card-pro"
|
||
data-duration="3"
|
||
data-track-index="1"
|
||
data-variable-values='{"title":"Enterprise","accent":"#22c55e"}'
|
||
></div>
|
||
```
|
||
|
||
Both instances keep the same source and receive different content.
|
||
|
||
## Advanced: render a version from data
|
||
|
||
Override top-level values from the CLI:
|
||
|
||
```bash
|
||
npx hyperframes render \
|
||
--variables '{"title":"Enterprise","accent":"#22c55e"}' \
|
||
--strict-variables \
|
||
--output enterprise.mp4
|
||
```
|
||
|
||
Use `--variables-file` for a JSON file and `--batch` when the same composition
|
||
must render once per data row. The [CLI reference](/packages/cli) covers batch
|
||
output, validation, and automation.
|
||
|
||
### Batch renders
|
||
|
||
Put one variable object per row in a JSON array, then use placeholders from the
|
||
row to name each output:
|
||
|
||
```json rows.json
|
||
[
|
||
{ "name": "acme", "title": "Acme Pro" },
|
||
{ "name": "northstar", "title": "Northstar Pro" }
|
||
]
|
||
```
|
||
|
||
```bash
|
||
npx hyperframes render \
|
||
--batch rows.json \
|
||
--strict-variables \
|
||
--output "renders/{name}.mp4"
|
||
```
|
||
|
||
Start with the default single-row concurrency. Increase `--batch-concurrency`
|
||
only after one real render is stable and the machine has enough memory for
|
||
several renders at once.
|
||
|
||
## What can't be a variable
|
||
|
||
Variables change content inside a composition. They do not change:
|
||
|
||
- the composition viewport;
|
||
- the root composition’s total render duration;
|
||
- frame rate;
|
||
- output format, codec, or quality;
|
||
- a parent or sibling composition unless values are passed to it explicitly.
|
||
|
||
Those choices are read from source or render settings before composition logic
|
||
runs.
|
||
|
||
## Check the contract
|
||
|
||
Run:
|
||
|
||
```bash
|
||
npx hyperframes lint
|
||
```
|
||
|
||
The linter catches malformed declarations, missing fields, wrong default types,
|
||
and invalid enum choices. `--strict-variables` turns undeclared or mistyped
|
||
render values into errors.
|
||
|
||
Continue to [Compositions](/concepts/compositions) for nesting or the
|
||
[HTML schema](/reference/html-schema) for the complete attribute contract.
|