mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-13 15:49:53 +00:00
fix(pr-to-video): enforce offline frame contract (#2383)
* fix(pr-to-video): enforce offline frame contract * fix(pr-to-video): tighten frame attribute contract
This commit is contained in:
@@ -26,7 +26,7 @@ Each packet provides:
|
||||
|
||||
**Retry** — if your context carries lint / validate feedback from a prior pass, read it first and re-author so none of those findings recur; treat each as a hard constraint.
|
||||
|
||||
**OUTPUT** — one `compositions/frames/<frame_id>.html` per assigned packet, each a self-contained sub-composition. After the last assigned file passes the self-check, stop — you do not edit `STORYBOARD.md`, mint audio, assemble the index, run the CLI, or report back. The orchestrator picks up the files and marks their `status`.
|
||||
**OUTPUT** — one `compositions/frames/<frame_id>.html` per assigned packet, each a bare template fragment. The first non-whitespace bytes are `<template`; the last are `</template>`. Never emit `<!doctype>`, `<html>`, `<head>`, `<body>`, or any markup outside that single template. After the last assigned file passes the self-check, stop — you do not edit `STORYBOARD.md`, mint audio, assemble the index, run the CLI, or report back. The orchestrator validates the files before assembly and marks their `status`.
|
||||
|
||||
## Mostly invented — you build the visual (except code blocks + the credits avatars)
|
||||
|
||||
@@ -80,7 +80,7 @@ Generic seek-safety + structure live in `hyperframes-core` (read it; not restate
|
||||
|
||||
You **can't** meaningfully run `hyperframes lint` / `validate` / `inspect` here: they operate on the **assembled project** (the `index.html` graph / bundle), and your frame isn't wired in yet — so they report on _other_ files, not yours (a false green). The **orchestrator** runs them at **Step 6, after assembly** (the correct unit), and **re-dispatches you with the finding** if your frame fails (see **Retry** above). So get it right on write: re-read your file against this checklist before finishing — the codes in parens are `hyperframes lint`'s and what the orchestrator may cite back (the rules behind them live in `hyperframes-core`):
|
||||
|
||||
- `missing_template_wrapper` / `missing_composition_id` — root is `<template>`-wrapped and carries `data-composition-id="<frame_id>"`.
|
||||
- `missing_template_wrapper` / `missing_composition_id` — the entire file is exactly one bare `<template>…</template>` fragment (no DOCTYPE/full document); its first element carries `data-composition-id="<frame_id>"` and a positive `data-duration` matching the packet.
|
||||
- **Template transport** — every `<style>` and `<script>` block, including the GSAP load, lives inside `<template>`.
|
||||
- `subcomposition_root_styled_by_class` — **style the frame root via `#root`, never a class on the `data-composition-id` element**: at render a class on the root gets scoped to a descendant selector that can't match it, so the **whole scene renders unstyled** (Studio preview still looks right — trust this rule, not the preview). Descendants use plain selectors.
|
||||
- **Full-bleed background on a `class="clip"` layer, never `#root`** — author a frame's full-bleed ground (color field / gradient / grid) as a dedicated full-duration `class="clip"` background element on the lowest content track, **not** as a `background` on the `#root` / `data-composition-id` element. At assembly the frame root is clip-gated to its scene window, so a background painted on the root is not a dependable full-frame ground — dark content can end up over the host `body` (black) and render invisible. The video's base ground is painted separately by the assembler from `frame.md`'s `canvas` color onto the index `#root`; your full-bleed clip rides on top of it.
|
||||
@@ -93,5 +93,5 @@ You **can't** meaningfully run `hyperframes lint` / `validate` / `inspect` here:
|
||||
- **No front-loading (not a slide)** — the shot's pieces reveal on their `voiceover` cues across the duration, not all fired at `t=0`; a non-still frame keeps content arriving rather than holding a full canvas from ~25%.
|
||||
- **Shot-sequence fidelity** — every Scene in the time-coded sequence is realized as a phase, the blueprint's signature move (unless `compose`) is present and recognizable, and the shot reveals to the voiceover (never front-loaded at `t=0`).
|
||||
- **Code-block cadence fits `data-duration`** — for a code beat, the `code-*` block's internal cadence is set so the full block completes within the frame's `data-duration` (a long snippet at the default per-character speed overruns — the code never finishes and the chrome beats never play; see `code-vocabulary.md`).
|
||||
- `font_family_without_font_face` — every font you name has a matching `@font-face` (or `@import`) **inside this file**. **Only use fonts that ship as files** with the project: the families declared in `frame.md` (their `.woff2` live in `assets/fonts/` or `capture/assets/fonts/` — point the `@font-face` `src` at the real file you find there). **Never name a font that has no file**, including system CJK / Japanese / Devanagari families (`Hiragino Sans`, `Yu Gothic`, `Noto Sans CJK`, `Noto Sans Devanagari`, …): the render machine is a clean headless Chrome with none of them installed, so the text silently falls back to a generic font and the typography is wrong in the MP4. For non-Latin or multilingual visible text, either use a shipped font that covers the script, or romanize / transliterate it (e.g. `日本語` → `Japanese`); if neither is possible it is out of scope for this frame — do not invent a font name.
|
||||
- `font_family_without_font_face` — every font you name has a matching local `@font-face` **inside this template**. Copy the auto-generated block from `frame.md`; the Claude preset's EB Garamond, Inter, and JetBrains Mono faces live in `assets/fonts/`. Never link Google Fonts and never name a family without a project file, including system CJK / Japanese / Devanagari families (`Hiragino Sans`, `Yu Gothic`, `Noto Sans CJK`, `Noto Sans Devanagari`, …): the render machine is clean headless Chrome, so absent faces silently fall back. For non-Latin visible text, use a shipped face that covers the script or romanize/transliterate it; otherwise it is out of scope.
|
||||
- **Keep-out + no-narration-text** (eyeball, no code) — nothing sits below the 83% cutoff; no narration sentence is rendered as visible text.
|
||||
|
||||
Reference in New Issue
Block a user