mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
Building on PR 1's getVariables() helper, this PR routes per-instance values into the correct sub-composition. Same composition source can now be embedded N times with different content via data-variable-values on each host element. How it works: - compositionLoader, before injecting wrapped scripts, layers the host element's data-variable-values JSON over the sub-comp's declared defaults (its own data-composition-variables) and writes the merged object to window.__hfVariablesByComp[compositionId]. Skipped when both sides are empty so the table only grows for instances that actually carry values. - compositionScoping's wrapper IIFE now takes a fourth parameter __hyperframes alongside the existing scoped document/gsap/window. The scoped __hyperframes shadows getVariables() to read from __hfVariablesByComp[__hfCompId], returning a fresh object each call so script mutations don't leak into the shared table. - Top-level scripts (not wrapped by compositionScoping) keep using the unscoped window.__hyperframes.getVariables(), which reads data-composition-variables defaults plus the CLI override (window.__hfVariables) — same path as PR 1. - readDeclaredDefaults is exported from getVariables.ts so the loader reuses the exact same defaults-extraction logic the helper uses for the top-level path. Inline templates (no separate <html> document root) get host overrides only — no declared defaults — since there's no separate <html> to read data-composition-variables from. External sub-comps fetched via data-composition-src get the full declared defaults + host overrides merge. Tests: 3 new compositionScoping tests covering scoped getVariables invocation, missing-entry fallback, and mutation isolation. 5 new compositionLoader tests covering merge order, declared-only path, empty-skip, invalid-host-JSON resilience, and per-instance scoping across two hosts sharing a source. 3 new getVariables tests covering the newly-public readDeclaredDefaults. All 622 core tests green. Docs: docs/concepts/compositions.mdx switched its sub-comp example from hand-rolled JSON.parse(host.dataset.variableValues) to the new __hyperframes.getVariables() pattern. data-attributes.mdx clarifies per-instance scoping behavior. This is PR 2 of a 4-PR stack. PR 3 adds schema validation + lint; PR 4 ships skill / scaffold updates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
107 lines
5.5 KiB
Plaintext
107 lines
5.5 KiB
Plaintext
---
|
|
title: Data Attributes
|
|
description: "Core attributes for controlling element timing and behavior."
|
|
---
|
|
|
|
Hyperframes uses HTML data attributes to control timing, media playback, and [composition](/concepts/compositions) structure. These are the declarative building blocks of every video.
|
|
|
|
## Timing Attributes
|
|
|
|
| Attribute | Example | Description |
|
|
|-----------|---------|-------------|
|
|
| `data-start` | `"0"` or `"intro"` | Start time in seconds, or a clip ID reference for [relative timing](#relative-timing) |
|
|
| `data-duration` | `"5"` | Duration in seconds. Required for images. Optional for video/audio (defaults to source duration). Not used on compositions. |
|
|
| `data-track-index` | `"0"` | Timeline track number. Controls z-ordering (higher = in front) and groups clips into rows. Clips on the same track cannot overlap. |
|
|
|
|
## Media Attributes
|
|
|
|
| Attribute | Example | Description |
|
|
|-----------|---------|-------------|
|
|
| `data-media-start` | `"2"` | Media playback offset / trim point in seconds. Default: `0` |
|
|
| `data-volume` | `"0.8"` | Audio/video volume, 0 to 1 |
|
|
| `data-has-audio` | `"true"` | Indicates video has an audio track |
|
|
|
|
## Composition Attributes
|
|
|
|
| Attribute | Example | Description |
|
|
|-----------|---------|-------------|
|
|
| `data-composition-id` | `"root"` | Unique ID for [composition](/concepts/compositions) wrapper (required on every composition) |
|
|
| `data-width` | `"1920"` | Composition width in pixels |
|
|
| `data-height` | `"1080"` | Composition height in pixels |
|
|
| `data-composition-src` | `"./intro.html"` | Path to external [composition](/concepts/compositions) HTML file |
|
|
| `data-variable-values` | `'{"title":"Hello"}'` | JSON object of values passed to a nested composition. Inside the sub-composition, read them via `window.__hyperframes.getVariables()` — the runtime layers these over the sub-comp's own `data-composition-variables` defaults and exposes the merged result on a per-instance basis (the same source can be embedded multiple times with different values). |
|
|
| `data-composition-variables` | `'[{"id":"title","type":"string","label":"Title","default":"Hello"}]'` | JSON array of declared variables (`id`, `type`, `label`, `default`). Drives Studio editing UI and provides defaults read by `window.__hyperframes.getVariables()`. The CLI flag `hyperframes render --variables '<json>'` overrides these defaults at top-level render time; host elements override them per-instance via `data-variable-values`. |
|
|
|
|
## Element Visibility
|
|
|
|
Add `class="clip"` to all timed elements so the runtime can manage their visibility lifecycle:
|
|
|
|
```html index.html
|
|
<h1 id="title" class="clip"
|
|
data-start="0" data-duration="5" data-track-index="0">
|
|
Hello World
|
|
</h1>
|
|
```
|
|
|
|
## Relative Timing
|
|
|
|
Instead of calculating absolute start times, a clip can reference another clip's `id` in its `data-start` attribute. This means "start when that clip ends":
|
|
|
|
```html index.html
|
|
<video id="intro" data-start="0" data-duration="10" data-track-index="0" src="..."></video>
|
|
<video id="main" data-start="intro" data-duration="20" data-track-index="0" src="..."></video>
|
|
<video id="outro" data-start="main" data-duration="5" data-track-index="0" src="..."></video>
|
|
```
|
|
|
|
`main` resolves to second 10, `outro` resolves to second 30. If `intro`'s duration changes, downstream clips shift automatically.
|
|
|
|
### Offsets (Gaps and Overlaps)
|
|
|
|
Add `+ N` or `- N` after the ID to offset from the end of the referenced clip:
|
|
|
|
```html index.html
|
|
<!-- 2-second gap after intro -->
|
|
<video id="scene-a" data-start="intro + 2" data-duration="20"
|
|
data-track-index="0" src="..."></video>
|
|
|
|
<!-- 0.5-second overlap with intro (crossfade) -->
|
|
<video id="scene-b" data-start="intro - 0.5" data-duration="20"
|
|
data-track-index="1" src="..."></video>
|
|
```
|
|
|
|
<Note>
|
|
Overlapping clips must be on different tracks -- clips on the same track cannot overlap in time.
|
|
</Note>
|
|
|
|
<Accordion title="Relative timing rules and constraints">
|
|
**Same composition only** -- references resolve within the clip's parent [composition](/concepts/compositions). You cannot reference a clip in a sibling or parent composition.
|
|
|
|
**No circular references** -- A cannot start after B if B starts after A. The resolver detects cycles and throws an error.
|
|
|
|
**Referenced clip must have a known duration** -- either an explicit `data-duration` or a duration inferred from source media. If the referenced clip has no known duration, the reference cannot resolve.
|
|
|
|
**Parsing rules** -- if the value is a valid number, it is treated as absolute seconds. Otherwise it is parsed as one of:
|
|
- `<id>` -- start when that clip ends
|
|
- `<id> + <number>` -- start N seconds after that clip ends
|
|
- `<id> - <number>` -- start N seconds before that clip ends
|
|
|
|
**Chain length** -- references can chain (`A` -> `B` -> `C`), but deeply nested chains make the timeline harder to reason about. Keep chains under 3-4 levels for readability.
|
|
</Accordion>
|
|
|
|
## Next Steps
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Compositions" icon="layer-group" href="/concepts/compositions">
|
|
How compositions use data attributes to define video structure
|
|
</Card>
|
|
<Card title="HTML Schema Reference" icon="book" href="/reference/html-schema">
|
|
Complete attribute reference with per-element details
|
|
</Card>
|
|
<Card title="GSAP Animation" icon="wand-magic-sparkles" href="/guides/gsap-animation">
|
|
Animate elements alongside data-attribute-driven timing
|
|
</Card>
|
|
<Card title="Common Mistakes" icon="triangle-exclamation" href="/guides/common-mistakes">
|
|
Pitfalls to avoid when setting up timing and attributes
|
|
</Card>
|
|
</CardGroup>
|