Skip to main content
Composition, design & animation
Compositions
The fundamental building block of a Hyperframes video.
A composition is an HTML file that describes a video. You write elements, give
them
Two rules make that work. The outer element needs The file it points at wraps everything in a Leading HTML comments are allowed before
The second card’s
Variables covers the types, the bindings that need no
script, CLI overrides, and which value wins. If you are building tooling on
A separate script file (
data-* timing attributes, and the framework turns them into frames.
index.html is the top-level composition. It can hold other compositions
inside it. There is no special “root” type — any composition can be imported
into any other.
How an HTML file becomes frames
Here is a whole video: a logo, then a video clip.index.html
data-composition-id, and
every timed element needs class="clip" so the runtime can hide it outside its
own window of time.
The clips add up to five seconds. At 30 frames per second — the default — that
is 150 frames, numbered 0 to 149:
Nothing plays in real time during a render. The renderer asks for frame 0, then
frame 1, and each answer is a single still picture. That is what makes
rendering deterministic.
What can go on the timeline
A clip is any element with timing attributes on it:<video>— video clips, B-roll, A-roll<img>— stills and overlays<audio>— music and sound effects<div data-composition-id="...">— another composition nested inside this one
Put one composition inside another
You can either point at a separate file or write the nested composition inline. Use a separate file when you want to reuse it.- External file
- Inline
data-composition-src names the file. The framework fetches it, pulls the
content out of its <template> tag, mounts it, runs its scripts, and
registers its timeline.Paths resolve from the project root, not from the file doing the
referencing. So a composition nested one level deep still writes
compositions/foo.html, never ../compositions/foo.html.index.html
<template>:compositions/intro-anim.html
<template>. Targeting this scene
with render -c compositions/intro-anim.html or
keyframes compositions/intro-anim.html --shot scene.png reuses its mount
from index.html, including the project’s library scripts.data-playback-start picks which moment of the child timeline shows first.
It defaults to 0. Trimming or splitting from the left pushes this offset
forward by the time elapsed multiplied by data-playback-rate, so the
nested animation keeps going instead of jumping back to its beginning.Timing inside the child file is local to that composition. If this host
starts at 10 and a child video starts at 2, the video starts at 12 on
the root timeline. Legacy projects that authored a media start in root time
can preserve it explicitly with data-hf-media-start-basis="global"; new
compositions should use local timing.Where the files live
project
index.html
compositions
intro-anim.html
caption-overlay.html
outro-title.html
assets
HTML sets the timing, scripts do the motion
Your HTML says what plays, when, and on which track, all through data attributes. Your scripts handle the creative part: effects, transitions, canvas, SVG, GSAP animation.Reuse one composition with different content
One source file can appear several times in the same video, each copy carrying its own text and colors. HyperFrames does not wiredata-var-* attributes into
your DOM or CSS for you — you do it in three steps:
- Declare each variable — id, type, default — on the sub-composition’s root
with
data-composition-variables. That root is the<html>element in a full-document composition, or the[data-composition-id]element in a template or fragment. - Pass each copy’s values on its host element with
data-variable-values. - Read them inside the composition with
window.__hyperframes.getVariables(), which layers the host’s values over the declared defaults, one copy at a time.
index.html
data-start="card-pro" means “start when that one ends”.
And the source file both cards share:
compositions/card.html
@hyperframes/core, extractCompositionMetadata() reads the same
data-composition-variables array — that is how the browser editor builds its editing UI.
Load a composition’s own files from its script
When a composition is mounted, asrc or href attribute that points at a
file next to it is rewritten to where that file lives, so
<img src="assets/logo.png"> keeps working. A path your script builds is a
plain string and is never rewritten, so resolve it with
window.__hyperframes.assetUrl(). It takes a path written relative to the
composition’s own file and returns a URL the page can load, whether the file is
mounted, previewed or opened on its own.
A path meant from the project root, such as assets/logo.png in a composition
at compositions/intro.html whose image sits in the project’s own assets/
folder, already resolves from the page. Leave it as a plain string:
assetUrl() would look for it beside the composition and miss.
compositions/globe/globe.html
<script src="...">) has no composition of its own to
resolve against. Resolve the URLs in the composition’s inline script and hand
them over, for example on a global the file reads.
