--- title: "Send to HyperFrames" description: "Author a Claude Design as a single-file HyperFrames composition for the \"Send to HyperFrames\" URL import." --- # Claude Design → "Send to HyperFrames" (Single-File Import) > This guide is **fully self-contained**: everything needed to author a valid "Send to HyperFrames" composition is inline here. Do not rely on fetching any other document — produce the composition from this guide alone. Your medium is a **HyperFrames composition**: plain HTML + CSS + a paused GSAP timeline. When the user clicks **"Send to HyperFrames"**, that composition is imported into a hosted HeyGen project, previewed in HyperFrames, and rendered to MP4 in the cloud. You produce a **valid first draft** — a HyperFrames motion-design agent enhances it afterward (sound, media, polish). You are not producing the final video. --- ## How this path differs from download-ZIP There are two ways a Claude Design composition can reach HyperFrames. **This guide is only about "Send to HyperFrames."** | | Download-ZIP flow | **Send to HyperFrames (this guide)** | | --- | --- | --- | | Wire format | multi-file ZIP (`index.html` + `fonts/` + README) | **one self-contained HTML file** | | How it travels | user downloads the ZIP | **the importer fetches one HTML** | | Assets | referenced from sibling files (`fonts/…`) | **resolvable from the one file: inline `data:` URIs (preferred) or a publicly-fetchable absolute URL** | | Next step | a coding agent polishes locally, renders via CLI | **enhanced inside HyperFrames; rendered in the cloud** | The single most important consequence: **there is no file tree on the other side.** A relative path or sibling-file reference (`fonts/…`, `uploads/…`) simply does not arrive. Every asset must be **resolvable**: an inline `data:` URI (preferred — the only fully self-contained form) or a publicly-fetchable absolute URL, never a relative path or local-file variable (see *Asset & fidelity rules*). --- ## The workflow you're feeding into 1. **You (Claude Design)** — author a valid HyperFrames composition as a single self-contained HTML. 2. **Send to HyperFrames** — one click. The importer fetches your HTML, validates it, and creates a hosted HeyGen project. **Import is free.** 3. **Enhance in HyperFrames** — a motion-design agent adds what your export can't: sound effects, background music, and (later) HeyGen media. This is the paid step. 4. **Render** — the cloud pipeline produces the MP4. Your job is step 1: a composition that imports cleanly and is a strong on-brand starting point. --- ## What you send: a single self-contained composition HTML One `.html` file. Everything the composition needs to display its own content must live **inside** that file: - All CSS inline (in `

Brand

Your tagline

0
Metric three

Closing line,

not another.

``` --- ## Animation pattern catalog (copy-paste) **The last argument of every `tl.to`/`tl.from` is the ABSOLUTE start time on the timeline (in seconds).** These snippets use a `SCENE_START` placeholder — replace it (and every selector) with your scene's real `data-start`, and keep each tween's **full active span** inside its scene window: `start + total_duration ≤ SCENE_START + data-duration`, where `total_duration` accounts for `repeat`, `yoyo` (each yoyo cycle doubles it), `repeatDelay`, and `stagger` spread. Do not paste the placeholder numbers literally. **Counter** — animate a number up (see the skeleton's `c2/c3/c4`): ```js var c = { v: 0 }; tl.to(c, { v: 1900000000000, duration: 0.9, ease: "power2.out", onUpdate: function () { document.getElementById("s3-stat").textContent = "$" + (c.v / 1e12).toFixed(1) + "T"; } }, /* SCENE_START */ 3.3); ``` **Character stagger** — wrap each char in ``, then: ```js tl.from(".char", { y: 60, autoAlpha: 0, duration: 0.5, ease: "power3.out", stagger: { each: 0.12, from: "start" } }, /* SCENE_START + 0.1 */ 0.1); ``` **Bar-chart fill:** ```js ["#bar1", "#bar2", "#bar3", "#bar4"].forEach(function (sel, i) { tl.from(sel, { scaleY: 0, transformOrigin: "bottom", duration: 0.6, ease: "expo.out" }, /* SCENE_START */ 3.3 + i * 0.15); }); ``` **Breathing float (mid-scene activity)** — note the yoyo+repeat doubles the span (0.6 × 2 = 1.2s), so from 4.9 it ends at 6.1, inside s4's 4.8-6.4 window: ```js tl.to("#s4-logo", { y: -5, duration: 0.6, ease: "sine.inOut", yoyo: true, repeat: 1 }, /* SCENE_START */ 4.9); ``` **SVG stroke draw** — `stroke-dasharray="440" stroke-dashoffset="440"` on the path, then: ```js tl.to("#s2-line", { strokeDashoffset: 0, duration: 1.0, ease: "power2.out" }, /* SCENE_START */ 1.7); ``` **Highlight sweep** — `background: linear-gradient(var(--accent),var(--accent)) no-repeat 0 85% / 0% 30%;`, then: ```js tl.to("#s5-headline", { backgroundSize: "100% 30%", duration: 0.6, ease: "power2.out" }, /* SCENE_START */ 6.6); ``` **CSS grain** (never SVG-filter grain — it taints html2canvas and breaks shaders in a cross-origin iframe): ```css .grain { position:absolute; inset:0; pointer-events:none; z-index:50; opacity:0.18; mix-blend-mode:overlay; background-image: radial-gradient(rgba(255,255,255,.08) 1px, transparent 1.2px), radial-gradient(rgba(0,0,0,.18) 1px, transparent 1.2px); background-size: 3px 3px, 5px 5px; background-position: 0 0, 1px 2px; } ``` --- ## Determinism & media rules (universal — violating these renders wrong or blank) The cloud renderer seeks the timeline frame-by-frame. Non-deterministic or self-driven animation fails. | Never | Use instead | | --- | --- | | `Math.random()` | seeded PRNG (only if truly needed) | | `Date.now()`, `performance.now()` | hard-coded timing or `tl.time()` in `onUpdate` | | `setInterval`, `setTimeout` | timeline tweens + `onUpdate` | | `requestAnimationFrame` | GSAP tweens | | `repeat: -1` | `repeat: Math.max(0, Math.floor(duration / cycle) - 1)` | | `stagger: { from: "random" }` | `from: "start"`, `"center"`, or `"end"` | | async timeline construction | build synchronously at page load | | `video.play()` / `audio.play()` | the framework owns playback | | `