๐Ÿ“„ Codex ่„šๆœฌๅบ“ โ† ่ฟ”ๅ›ž็›ฎๅฝ• โฌ‡ ไธ‹่ฝฝ .md
๐Ÿ“ 0120-hyperframes-video ๐Ÿ“… 2026-10-03

HyperFrames Schema

Reference for generating and editing HyperFrames HTML compositions. This is your source of truth for how to author compositions.

Overview

HyperFrames uses HTML as the source of truth for describing a video:

Framework-Managed Behavior

The framework reads data attributes and automatically manages:

Mounting and unmounting controls presence, not appearance. A clip that is mounted is on screen; a clip that is unmounted is not. Transitions (fade in, slide in, etc.) are separate โ€” they are animated in scripts and happen after a clip is mounted or before it is unmounted.

The framework does not handle transitions, effects, or visual animation โ€” those are driven by GSAP in JavaScript.

Do not manually call video.play(), video.pause(), set audio.currentTime, or mount/unmount clips in scripts. The framework owns media playback and clip lifecycle. Animating visual properties like opacity or transform for transitions is fine โ€” that's what scripts are for.

Viewport

The root composition must declare its intended render dimensions using data-width and data-height attributes. Common sizes:

e.g.,

<div id="main" data-composition-id="my-video" data-start="0" data-width="1920" data-height="1080">
  <!-- clips -->
</div>

Every composition's container is full-screen within the viewport by default. The framework applies full-screen sizing to composition containers automatically.

To position or size individual clips (e.g., picture-in-picture, overlay placement), use standard CSS on the element.

Compositions

A composition is the fundamental grouping unit in HyperFrames. Every clip โ€” video, image, audio โ€” must live inside a composition. The index.html file is itself a composition (the top-level one), and it can contain nested compositions within it. Any composition can be imported into another composition as a sub-composition โ€” there is no special "root" type.

A composition carries the same core attributes as any other clip (id, data-start, data-track-index), so it can be placed and timed on a timeline just like a video or image. A composition's length is determined by its GSAP timeline โ€” there is no data-duration on compositions. This means compositions can be nested: a composition clip inside another composition behaves like a self-contained video within the parent timeline.

<div id="comp-1" data-composition-id="my-video" data-start="0" data-width="1920" data-height="1080">
  <!-- Clips live inside the composition -->
  <video id="el-1" data-start="0" data-duration="10" data-track-index="0" src="..."></video>
  <video id="el-2" data-start="el-1" data-duration="8" data-track-index="0" src="..."></video>
  <img id="el-3" data-start="5" data-duration="4" data-track-index="1" src="..." />
  <audio id="el-4" data-start="0" data-duration="30" data-track-index="2" src="..." />

  <!-- Nested composition (e.g. a motion graphic or title sequence) -->
  <div id="el-5" data-composition-id="intro-anim" data-start="0" data-track-index="3">
    <!-- its own clips, timeline, and script -->
    <script src="intro-anim.js"></script>
  </div>
</div>

Note: data-width and data-height are only required on the root composition. Nested compositions inherit the viewport dimensions.

Clip Types

A clip is any discrete block on the timeline. We represent clips as HTML elements and apply data-attributes to describe them.

HTML Attributes

All Clips

Media Clips (video, audio)

Composition Clips

Compositions do not use data-duration. Their duration is determined by their GSAP timeline.

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." The referenced clip must be in the same composition and must have a known duration (either an explicit data-duration or an inferred duration from the source media).

Basic Sequential Clips

<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 to 15, main and outro shift automatically.

Offsets (gaps and overlaps)

Add + N or - N after the ID to offset from the end of the referenced clip:

<!-- intro ends at 10. "intro + 2" = 10 + 2 = starts at second 12 (2s gap) -->
<video
  id="scene-a"
  data-start="intro + 2"
  data-duration="20"
  data-track-index="0"
  src="..."
></video>

<!-- intro ends at 10. "intro - 0.5" = 10 - 0.5 = starts at second 9.5 (0.5s overlap for crossfade) -->
<!-- Different track because clips on the same track cannot overlap -->
<video
  id="scene-b"
  data-start="intro - 0.5"
  data-duration="20"
  data-track-index="1"
  src="..."
></video>

Rules

Video Clips

Full-screen or positioned video clips. Videos sync their playback to the timeline position.

<video
  id="el-1"
  data-start="0"
  data-duration="15"
  data-track-index="0"
  src="./assets/video.mp4"
></video>

Image Clips

Static images that appear for a duration.

<img id="el-2" data-start="5" data-duration="4" data-track-index="1" src="./assets/video.mp4" />

Audio Clips

Background music or sound effects. Audio clips are invisible.

<audio
  id="el-4"
  data-start="0"
  data-duration="30"
  data-track-index="2"
  src="./assets/music.mp3"
></audio>

Two Layers: Primitives and Scripts

Every composition โ€” master or sub โ€” has the same two layers:

Both layers are available to every composition. The schema defines the primitives and the timeline contract; scripts handle visual creativity on top of that.

Warning: Never use scripts to play/pause/seek media elements or to show/hide clips based on timing. The framework does this automatically from data-start, data-duration, and data-media-start. Scripts that duplicate this behavior will conflict with the framework.

Script Isolation

Each composition's script is scoped to that composition. For sub-compositions, external JS files are the natural way to keep them self-contained and reusable:

<div id="el-5" data-composition-id="intro-anim" data-start="0" data-track-index="2">
  <script src="intro-anim.js"></script>
</div>

Inline scripts are fine when the script belongs to that composition. The JS file itself is the documentation for what a composition does โ€” the schema doesn't need to describe its internals.

The only required file is index.html. Every composition must have at least a script to create and register its GSAP timeline.

Top-Level Composition

The top-level composition is the index.html entry point. It acts as the conductor โ€” sequencing clips and placing sub-composition timelines into an overall master timeline. It can technically do anything in its script, but its primary purpose is high-level orchestration. Any composition can serve as a top-level composition or be nested into another โ€” there is no structural difference.

<div id="comp-1" data-composition-id="my-video" data-start="0" data-width="1920" data-height="1080">
  <video id="el-1" data-start="0" data-duration="10" data-track-index="0" src="..."></video>
  <video id="el-2" data-start="el-1" data-duration="8" data-track-index="0" src="..."></video>
  <img id="el-3" data-start="5" data-duration="4" data-track-index="1" src="..." />
  <audio id="el-4" data-start="0" data-duration="30" data-track-index="2" src="..." />

  <div id="el-5" data-composition-id="intro-anim" data-start="0" data-track-index="3">
    <script src="intro-anim.js"></script>
  </div>

  <script>
    // Just register the timeline - framework auto-nests sub-compositions
    const tl = gsap.timeline({ paused: true });
    window.__timelines["my-video"] = tl;
  </script>
</div>

Sub-Compositions

Sub-compositions are a spectrum. One might simply group a few primitive clips. Another might be a fully custom program with its own HTML, CSS, and JavaScript โ€” creating, animating, and destroying DOM however it sees fit. There are no categories or constraints on what a sub-composition does internally. All compositions default to full-screen within the viewport. The only rule: it must be driven by a GSAP timeline and export it.

Wrapping Dynamic Content in Compositions

Critical Rule: All visual content must live inside a composition with data attributes to appear in the timeline.

When you have dynamic or script-animated content (captions, emojis, overlays, text animations), wrap them in a composition element with data-start, data-duration (or let the timeline determine duration), and data-track-index. The children inside can be freely created and animated via JavaScriptโ€”they don't need individual data attributes.

Wrong: Dynamic content outside a composition

<!-- BAD: captions-container is not a composition - won't appear in timeline -->
<div id="ui-layer">
  <div id="captions-container">
    <!-- Dynamically created caption groups via JS -->
  </div>
  <div class="emoji" id="emoji-1">๐Ÿคฉ</div>
</div>

<script>
  // These animations work visually but elements don't appear in timeline
  tl.to(".caption-group", { opacity: 1 }, 0.5);
  tl.to("#emoji-1", { scale: 1.2 }, 2);
</script>

Correct: Dynamic content wrapped in compositions

<!-- GOOD: Each logical group is a composition that appears in timeline -->
<div id="captions-comp" data-composition-id="captions" data-start="0" data-track-index="5">
  <!-- Children created/animated by script - no data attributes needed -->
  <div id="captions-container"></div>
  <script>
    const captionTL = gsap.timeline({ paused: true });
    // Dynamically create and animate caption groups...
    window.__timelines["captions"] = captionTL;
  </script>
</div>

<div id="emojis-comp" data-composition-id="emojis" data-start="0" data-track-index="6">
  <div class="emoji" id="emoji-1">๐Ÿคฉ</div>
  <div class="emoji" id="emoji-2">๐Ÿ”๏ธ</div>
  <script>
    const emojiTL = gsap.timeline({ paused: true });
    emojiTL.to("#emoji-1", { opacity: 1, scale: 1.2 }, 2);
    emojiTL.to("#emoji-2", { opacity: 1, scale: 1.2 }, 4);
    window.__timelines["emojis"] = emojiTL;
  </script>
</div>

When to create separate compositions

The composition appears in the timeline with its start time and duration (determined by its GSAP timeline). Everything inside is managed by the script but inherits the composition's timeline position.

Timeline Contract

The framework initializes window.__timelines = {} before any scripts run. Every composition must have a script that creates a GSAP timeline and registers it:

const tl = gsap.timeline({ paused: true });
// ... add tweens, nested timelines, etc.
window.__timelines["<data-composition-id>"] = tl;

Rules

What NOT to do

// UNNECESSARY - the framework does this automatically
if (window.__timelines["captions"]) {
  masterTL.add(window.__timelines["captions"], 0);
}

Just register your timeline in window.__timelines and the framework handles the rest.

Output Checklist

็”ฑ Codex ็”Ÿๆˆ ยท hob0003 ยท ็”ฑ Codex ่‡ชๅŠจ็”Ÿๆˆ ยท ๅฎžๆ—ถๅŒๆญฅ