pr-to-video

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

pr-to-video - dispatch entry

pr-to-video - 调度入口

Input is a GitHub pull request (a code change), supplied as a PR URL, an
<owner>/<repo>#<N>
ref, or "this PR" while a repo with an open PR is checked out. Output is a code-change explainer: what shipped, why, and how it works — rendered from the diff/commits as before-after, diff-highlight, file-tree, and impact scenes. Default length up to ~3 min (sweet spot ~30-90s); a genuinely longer or exhaustive every-file walkthrough (5 min+) is a different register →
/general-video
. There is no website scrape and no headless Chrome for ingest — ingest is the
gh
CLI. The shipped style preset is always claude (warm editorial; signature navy code window).
Confirm the route before Step 0. This skill explains a GitHub pull request (a code change read via
gh
). If the input is a marketing / product site
/product-launch-video
; a general website
/website-to-video
; a topic / article with no PR
/faceless-explainer
; a whole-repo tour or multi-PR release
/general-video
. Out of scope: live / at-render-time data — PR facts are read once at author time and baked in. Handed a non-PR input, or unsure? Read
/hyperframes-read-first
first.
This workflow owns only the PR-specific front (ingest + story-design); every phase marked shared reuses the engine copied from faceless-explainer unchanged (it lives under this skill's own
scripts/
+
agents/
+
phases/
, so
<SKILL_DIR>
resolves to pr-to-video).
All artifacts go to
PROJECT_DIR = videos/<project-name>/
(created in Step 0); all paths below are relative to it. Dispatch is harness-portable: before the first subagent dispatch, read
<SKILL_DIR>/../hyperframes-core/references/subagent-dispatch.md
once — it maps the dispatch verbs (parallel fan-out / background / wait) to your harness's primitives; a concurrency cap below N means waves of the cap size, never fewer workers. This file is a binding runbook, not background reading: execute the steps in order and produce every phase artifact with its designated script or agent role — do not substitute a freestyle pipeline, and do not skip a pause step because the request seems clear. A step you cannot perform → stop and report.
PhaseExecutionPrimary artifactDetailed flow
initBash
hyperframes.json
Step 0
ingest (own)Bash (
gh
CLI +
ingest.mjs
+
fetch-people-avatars.mjs
, NO agent, NO scrape)
capture/pr.json
+
diff.patch
+
extracted/{tokens.json,visible-text.txt,people.json}
+
public/avatars/
Step 1
design-system (shared)Bash (no agent, deterministic
claude
)
design-system/design.html
+
chunks/
Step 1b
story-design (own)subagent
narrator_scripts.json
agents/story-design.md
audio (shared)
audio.mjs
in Bash
audio_meta.json
phases/audio/guide.md
visual-design (shared)subagent
section_plan.md
agents/visual-design.md
prep (shared)
prep.mjs
in Bash
group_spec.json
scripts/prep.mjs
captions (shared, det.)
captions.mjs group
->
captions.mjs html
in Bash (no subagent)
caption_groups.json
+
compositions/captions.html
scripts/captions.mjs
scenes (shared)N x subagent (parallel)
compositions/scene_*.html
or
compositions/group_w*.html
agents/hyperframes-scene.md
finalize (shared)Bash prelude (wait-bgm + assemble + inject/verify-transitions + hoist-videos + sfx-verify + preflight) -> finalize subagent (fix brief findings in place + one lean contact-sheet look + render)
renders/video.mp4
Step 7 /
agents/hyperframes-finalize.md
输入为 GitHub Pull Request(代码变更),可通过 PR URL、
<owner>/<repo>#<N>
引用,或在已检出含未合并PR的仓库中输入“this PR”来提供。输出为 代码变更讲解视频:包含已上线内容、变更原因及工作原理——通过差异/提交记录渲染为前后对比、差异高亮、文件树及影响场景。默认时长 最长约3分钟(最佳时长为30-90秒);若需5分钟以上的详尽逐文件讲解,请使用
/general-video
。本工作流不支持网站抓取及无头Chrome采集——采集环节仅使用
gh
CLI。默认启用的风格预设始终为 claude(温暖的编辑风格;标志性深蓝色代码窗口)。
步骤0前请确认路由。本工具用于讲解 GitHub Pull Request(通过
gh
读取的代码变更)。若输入为 营销/产品网站 → 使用
/product-launch-video
;若为 通用网站 → 使用
/website-to-video
;若为 无PR的主题/文章 → 使用
/faceless-explainer
;若为 全仓库漫游或多PR版本发布 → 使用
/general-video
超出范围:实时渲染数据——PR信息仅在创建时读取一次并固化。若收到非PR输入或不确定路由,请先查看
/hyperframes-read-first
本工作流仅负责PR专属的前端环节(采集 + 故事设计);所有标记为_shared_的阶段均复用来自faceless-explainer的引擎(该引擎位于本工具的
scripts/
+
agents/
+
phases/
目录下,因此
<SKILL_DIR>
指向pr-to-video)。
所有产物均存储至
PROJECT_DIR = videos/<project-name>/
(在步骤0中创建);以下所有路径均为该目录的相对路径。调度支持多种执行环境:在首次子代理调度前,请阅读
<SKILL_DIR>/../hyperframes-core/references/subagent-dispatch.md
一次——该文档将调度动词(并行分发/后台执行/等待)映射至执行环境的原语;若并发上限低于N,则按上限分批执行,不得减少工作进程数量。本文件为绑定运行手册,而非背景资料:请按顺序执行步骤并生成每个阶段的指定产物,不得替换为自由式流水线,也不得因请求看似明确而跳过暂停步骤。若无法执行某一步骤,请停止并上报。
阶段执行方式主要产物详细流程
initBash
hyperframes.json
步骤0
采集(专属)Bash(
gh
CLI +
ingest.mjs
+
fetch-people-avatars.mjs
,不使用代理,不抓取)
capture/pr.json
+
diff.patch
+
extracted/{tokens.json,visible-text.txt,people.json}
+
public/avatars/
步骤1
设计系统(共享)Bash(不使用代理,确定性
claude
风格)
design-system/design.html
+
chunks/
步骤1b
故事设计(专属)子代理
narrator_scripts.json
agents/story-design.md
音频(共享)Bash中执行
audio.mjs
audio_meta.json
phases/audio/guide.md
视觉设计(共享)子代理
section_plan.md
agents/visual-design.md
预处理(共享)Bash中执行
prep.mjs
group_spec.json
scripts/prep.mjs
字幕(共享,确定性)Bash中执行
captions.mjs group
captions.mjs html
(不使用子代理)
caption_groups.json
+
compositions/captions.html
scripts/captions.mjs
场景(共享)N个子代理并行执行
compositions/scene_*.html
compositions/group_w*.html
agents/hyperframes-scene.md
最终处理(共享)Bash前置流程(等待背景音乐 + 组装 + 注入/验证转场 + 提升视频层级 + 音效验证 + 预检)→ 最终处理子代理(修复预检问题 + 生成精简预览图 + 渲染)
renders/video.mp4
步骤7 /
agents/hyperframes-finalize.md

Prerequisites

前置条件

macOS Apple Silicon or Linux x64. System tools:
brew install python@3.11 node ffmpeg
(use Homebrew Python, not
/usr/bin/python3
, or
pip install
is blocked by PEP 668); then
npx hyperframes doctor
once (downloads Chrome — needed for snapshot/render, not for ingest). The rendered overlap gate (
scripts/check-overlap.mjs
, run in worker self-checks and preflight) reuses that same cached Chrome — it never downloads a browser; its only dep is the
puppeteer-core
npm module, ensured once before scene fan-out (Step 5.5,
--ensure-deps
, ~5s, no full
puppeteer
install). CLIs:
gh
(GitHub CLI, authenticated —
gh auth status
must pass) and
hyperframes
. Optional cloud keys (else local fallbacks) — inject in Step 0.5:
Key / requirementUsed forDefault / fallback
gh auth status
OK
Reading the PR (public or private)required — fail fast with the auth hint
HEYGEN_API_KEY
(or
hyperframes auth login
)
TTS (cloud, word-level timestamps)voice: auto (first English starfish voice; override
--voice
)
ELEVENLABS_API_KEY
TTS (cloud; needs
pip install elevenlabs
)
voice
21m00Tcm4TlvDq8ikWAM
(Rachel)
neither, and not logged inTTSlocal Kokoro, voice
am_michael
(non-English: pass
--voice
)
GEMINI_API_KEY
/
GOOGLE_API_KEY
(aliases)
Lyria BGMunset -> local MusicGen (first run downloads ~300 MB)
需使用macOS Apple Silicon或Linux x64系统。系统工具:
brew install python@3.11 node ffmpeg
(请使用Homebrew安装的Python,不要使用
/usr/bin/python3
,否则PEP 668会阻止
pip install
);然后执行一次
npx hyperframes doctor
(下载Chrome——仅用于快照/渲染,不用于采集)。渲染重叠检查工具(
scripts/check-overlap.mjs
,在工作进程自检和预检中运行)复用同一缓存的Chrome——无需重复下载浏览器;仅依赖
puppeteer-core
npm模块,将在场景分发前(步骤5.5,
--ensure-deps
,约5秒)自动安装,无需完整安装
puppeteer
。CLI工具:
gh
(GitHub CLI,需已认证——
gh auth status
必须通过)和
hyperframes
。可选云密钥(无则使用本地 fallback)——在步骤0.5中注入:
密钥/要求用途默认值/降级方案
gh auth status
验证通过
读取PR(公开或私有)必填——若未通过则立即提示认证方法
HEYGEN_API_KEY
(或
hyperframes auth login
文本转语音(云端,支持按单词生成时间戳)语音:自动选择(首个英文starfish语音;可通过
--voice
覆盖)
ELEVENLABS_API_KEY
文本转语音(云端;需安装
pip install elevenlabs
语音
21m00Tcm4TlvDq8ikWAM
(Rachel)
未设置上述密钥且未登录文本转语音本地Kokoro引擎,语音
am_michael
(非英文场景需传入
--voice
GEMINI_API_KEY
/
GOOGLE_API_KEY
(别名)
生成Lyria背景音乐未设置则使用本地MusicGen(首次运行需下载约300MB模型)

Flow

流程

Step 0.0 - Confirm the brief (ALWAYS ask one round, then build)

步骤0.0 - 确认需求(必须询问一轮后再执行)

Before Step 0, always pause and ask the brief in one message, then wait for the user — never skip this, even for a request that looks complete. Lead with a recommended default for each field and pre-fill anything the user already gave (confirm it rather than re-asking blindly): the angle (changelog / feature reveal / fix / refactor — default: infer from the PR), the audience (developers vs general users — default: developers), length (default ~60-90s), and — if
/hyperframes-read-first
didn't set them — aspect (default 16:9) and language. Style is always
claude
. Proceed to Step 0 only after the user replies; a "go" / "use the defaults" is a valid reply that accepts every default.
在步骤0之前,必须暂停并通过一条消息确认需求,等待用户回复后再继续——即使请求看似完整也不得跳过此步骤。针对每个字段提供推荐默认值,并预填充用户已提供的内容(确认而非重复询问):角度(变更日志/功能发布/修复/重构——默认:从PR中推断)、受众(开发者 vs 普通用户——默认:开发者)、时长(默认约60-90秒),以及——若
/hyperframes-read-first
未设置——宽高比(默认16:9)和语言。风格始终为
claude
。仅在用户回复后才可进入步骤0;“开始”/“使用默认值”为有效回复,表示接受所有默认设置。

Step 0 - Initialize the video project

步骤0 - 初始化视频项目

cwd is the agent workspace root (e.g.
/tmp/pr-video-...
). Write all video artifacts under
PROJECT_DIR = videos/<project-name>/
.
<project-name>
: use the directory the user gave (e.g.
Use ./videos/retry-pr
), else a short kebab-case name derived from the PR (
<repo>-pr-<N>
, e.g.
widgets-pr-1187
). Not the workspace basename or a timestamp.
Only when
$PROJECT_DIR/hyperframes.json
is absent:
bash
PROJECT_DIR="${PR_VIDEO_DIR:-videos/<project-name>}"
mkdir -p "$(dirname "$PROJECT_DIR")"
npx hyperframes init "$PROJECT_DIR" --non-interactive --skip-skills --example=blank
hyperframes init
drops a generic
AGENTS.md
/
CLAUDE.md
into
$PROJECT_DIR
; leave them in place — they are agent scaffolding for whoever opens the finished project later.
Constraints: never run
hyperframes init
/ generate
AGENTS.md
/
CLAUDE.md
in the workspace root; never nest another
hyperframes/
inside
PROJECT_DIR
; every Bash command (master + subagents) is a
(cd "$PROJECT_DIR" && ...)
subshell — never bare
cd
.
当前工作目录为代理工作区根目录(例如
/tmp/pr-video-...
)。所有视频产物均写入
PROJECT_DIR = videos/<project-name>/
目录下。
<project-name>
:使用用户指定的目录(例如
Use ./videos/retry-pr
),否则使用从PR衍生的短横线命名(
<repo>-pr-<N>
,例如
widgets-pr-1187
)。不得使用工作区基名或时间戳。
仅当
$PROJECT_DIR/hyperframes.json
不存在时执行:
bash
PROJECT_DIR="${PR_VIDEO_DIR:-videos/<project-name>}"
mkdir -p "$(dirname "$PROJECT_DIR")"
npx hyperframes init "$PROJECT_DIR" --non-interactive --skip-skills --example=blank
hyperframes init
会在
$PROJECT_DIR
中生成通用的
AGENTS.md
/
CLAUDE.md
请保留这些文件——它们是后续打开成品项目时的代理脚手架。
约束:不得在工作区根目录运行
hyperframes init
/生成
AGENTS.md
/
CLAUDE.md
;不得在
PROJECT_DIR
内嵌套另一个
hyperframes/
目录;所有Bash命令(主进程+子代理)均需在
(cd "$PROJECT_DIR" && ...)
子shell中执行——不得直接使用
cd
命令。

Step 0.5 - API key guidance

步骤0.5 - API密钥引导

Skip if
$PROJECT_DIR/.env
exists or
context.log
is non-empty (= not the first run). Otherwise first detect what's available (HeyGen TTS on if
$HEYGEN_API_KEY
/
$HYPERFRAMES_API_KEY
set or
~/.heygen/credentials
exists from
hyperframes auth login
; ElevenLabs / Gemini only if their env keys set), then always pause and offer the menu — wait for the user; do not proceed on your own even when a workable config is detected (the user may want to add a key like Gemini). State what's detected, then: paste keys (→ Write
$PROJECT_DIR/.env
, one
KEY=value
per line, overwrite same-name) / "go" (proceed with what's configured — env,
.env
, or
hyperframes auth login
) / "skip" (proceed with local fallbacks for anything unconfigured). Then proceed to Step 1.
$PROJECT_DIR/.env
已存在或
context.log
非空(非首次运行),则跳过此步骤。否则先检测可用配置(若设置了
$HEYGEN_API_KEY
/
$HYPERFRAMES_API_KEY
或存在
~/.heygen/credentials
(来自
hyperframes auth login
),则启用HeyGen TTS;仅当设置了对应环境密钥时才启用ElevenLabs/Gemini),然后必须暂停并提供选项菜单——等待用户回复,即使检测到可用配置也不得自行继续(用户可能希望添加如Gemini等密钥)。说明已检测到的配置,然后提供选项:粘贴密钥(→ 写入
$PROJECT_DIR/.env
,每行一个
KEY=value
,覆盖同名密钥)/“开始”(使用当前配置——环境变量、
.env
hyperframes auth login
配置)/“跳过”(对未配置项使用本地降级方案)。之后进入步骤1。

Step 1 - Ingest (Bash, NO agent, NO scrape)

步骤1 - 采集(Bash,不使用代理,不抓取)

Resolve the PR ref and pull structured facts with
gh
, then fold them into the synthetic capture package the shared backend expects (mirrors faceless-explainer's no-scrape scaffold).
gh
runs here, in the orchestrator, so auth / not-found / private-repo errors surface with gh's own stderr;
ingest.mjs
is a pure offline transform.
bash
undefined
解析PR引用并使用
gh
提取结构化信息,然后将其转换为共享后端所需的合成采集包(镜像faceless-explainer的无抓取架构)。
gh
编排器中运行,因此认证/未找到/私有仓库错误会直接通过gh的stderr输出;
ingest.mjs
为纯离线转换工具。
bash
undefined

PR ref: a full URL, "<owner>/<repo>#<N>", or "<N>" inside a checked-out repo.

PR引用:完整URL、"<owner>/<repo>#<N>",或已检出仓库中的"<N>"

PR="<url | owner/repo#N | N>"
PR="<url | owner/repo#N | N>"

Fail fast if gh is not authenticated.

若gh未认证则立即失败

gh auth status || { echo "gh not authenticated — run: gh auth login"; exit 1; }
(cd "$PROJECT_DIR" && mkdir -p capture/extracted capture/assets) (cd "$PROJECT_DIR" && gh pr view "$PR"
--json number,title,body,author,url,baseRefName,headRefName,commits,files,additions,deletions,changedFiles,labels,reviews,latestReviews,comments,assignees,reviewDecision,mergedBy \
capture/pr.json) (cd "$PROJECT_DIR" && gh pr diff "$PR" > capture/diff.patch)
gh auth status || { echo "gh未认证——请执行:gh auth login"; exit 1; }
(cd "$PROJECT_DIR" && mkdir -p capture/extracted capture/assets) (cd "$PROJECT_DIR" && gh pr view "$PR"
--json number,title,body,author,url,baseRefName,headRefName,commits,files,additions,deletions,changedFiles,labels,reviews,latestReviews,comments,assignees,reviewDecision,mergedBy \
capture/pr.json) (cd "$PROJECT_DIR" && gh pr diff "$PR" > capture/diff.patch)

Fold pr.json + diff.patch into tokens.json (colors:[] → claude native palette) +

将pr.json + diff.patch转换为tokens.json(colors:[] → claude原生调色板) +

visible-text.txt (the narrative brief) + people.json (PR author + commit authors w/ counts +

visible-text.txt(叙事简介) + people.json(PR作者 + 提交作者及提交次数 +

reviewers / commenters / assignees, bot-filtered + deduped, each with a GitHub avatar URL).

审核者/评论者/被指派者,已过滤机器人并去重,每人含GitHub头像URL)。

(The PR
author
is only the opener; commit authors from commits[].authors[] are tracked too.)

(PR
author
仅指创建者;提交作者从commits[].authors[]中追踪。)

ingest is OFFLINE.

采集过程为离线操作。

(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/ingest.mjs
--pr-json ./capture/pr.json --diff ./capture/diff.patch --out-dir ./capture/extracted)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/ingest.mjs
--pr-json ./capture/pr.json --diff ./capture/diff.patch --out-dir ./capture/extracted)

Network step (the people front's only one — ingest stays offline): download each

网络步骤(仅人物头像部分需要——采集其余部分仍为离线):下载每位

contributor's GitHub avatar to public/avatars/<login>.png for an optional credits /

贡献者的GitHub头像至public/avatars/<login>.png,用于可选的致谢/出品人结尾。

shipped-by close. Best-effort — a missing avatar or offline run never blocks (exit 0).

尽力而为——头像缺失或离线运行不会阻塞流程(退出码为0)。

Avatars + that close are the ONE place pr-to-video relaxes the faceless default.

头像及该结尾是pr-to-video唯一打破faceless默认设置的地方。

(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/fetch-people-avatars.mjs
--people ./capture/extracted/people.json)

Validation:

```bash
[ -s "$PROJECT_DIR/capture/pr.json" ] && \
[ -s "$PROJECT_DIR/capture/diff.patch" ] && \
[ -s "$PROJECT_DIR/capture/extracted/tokens.json" ] && \
[ -s "$PROJECT_DIR/capture/extracted/visible-text.txt" ] && \
[ -s "$PROJECT_DIR/capture/extracted/people.json" ] && \
[ -d "$PROJECT_DIR/capture/assets" ] && echo ok || echo missing
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/fetch-people-avatars.mjs
--people ./capture/extracted/people.json)

验证:

```bash
[ -s "$PROJECT_DIR/capture/pr.json" ] && \
[ -s "$PROJECT_DIR/capture/diff.patch" ] && \
[ -s "$PROJECT_DIR/capture/extracted/tokens.json" ] && \
[ -s "$PROJECT_DIR/capture/extracted/visible-text.txt" ] && \
[ -s "$PROJECT_DIR/capture/extracted/people.json" ] && \
[ -d "$PROJECT_DIR/capture/assets" ] && echo ok || echo missing

public/avatars/ is best-effort — its absence is NOT a failure (no avatars resolved / offline).

public/avatars/为尽力而为项——缺失不会导致失败(未解析到头像或离线)。


If `gh` errors (auth / not found / private), report the exact stderr and stop — **do not fabricate PR contents**. If `ingest.mjs` exits 1, read its stderr (usually a malformed `pr.json`), fix, rerun (deterministic, finishes instantly). `fetch-people-avatars.mjs` always exits 0; if avatars are missing, story-design simply has no credits scene to author.

若`gh`报错(认证/未找到/私有仓库),则输出准确的stderr信息并停止——**不得伪造PR内容**。若`ingest.mjs`退出码为1,则读取其stderr(通常为`pr.json`格式错误),修复后重新运行(确定性操作,瞬间完成)。`fetch-people-avatars.mjs`始终返回0;若头像缺失,故事设计环节则不会生成致谢场景。

Step 1b - Design system (Bash, NO agent, deterministic — SHARED)

步骤1b - 设计系统(Bash,不使用代理,确定性——共享)

Three deterministic commands produce a fully-styled
design.html
+ chunks against the synthetic input, with the claude preset (its
code-window
/
number-lockup
/
stat-card
components are the PR visual vocabulary):
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/phases/design-system/scripts/build-design.mjs ./design-system --no-emit --style claude)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/phases/design-system/scripts/build-design.mjs ./design-system --style claude)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/phases/design-system/scripts/emit-chunks.mjs ./design-system)
Validation:
bash
[ -s "$PROJECT_DIR/design-system/inference.json" ] && \
[ -s "$PROJECT_DIR/design-system/design.html" ] && \
[ -s "$PROJECT_DIR/design-system/chunks/index.json" ] && echo ok || echo missing
If any is missing, read the build-design / emit-chunks stderr, fix the invocation, and rerun (deterministic, finishes in seconds).
通过三个确定性命令,基于合成输入生成完全样式化的
design.html
+ 代码块,使用claude预设(其
code-window
/
number-lockup
/
stat-card
组件为PR视觉词汇):
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/phases/design-system/scripts/build-design.mjs ./design-system --no-emit --style claude)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/phases/design-system/scripts/build-design.mjs ./design-system --style claude)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/phases/design-system/scripts/emit-chunks.mjs ./design-system)
验证:
bash
[ -s "$PROJECT_DIR/design-system/inference.json" ] && \
[ -s "$PROJECT_DIR/design-system/design.html" ] && \
[ -s "$PROJECT_DIR/design-system/chunks/index.json" ] && echo ok || echo missing
若任一文件缺失,则读取build-design/emit-chunks的stderr信息,修复调用方式后重新运行(确定性操作,数秒内完成)。

Step 2 - Story-design (subagent) — OWN

步骤2 - 故事设计(子代理)——专属

Dispatch one subagent. prompt = full contents of
agents/story-design.md
+ the
## Dispatch context
below, passed through verbatim:
SKILL_DIR: <absolute path>
PROJECT_DIR: <video project root>
Schema validator: <SKILL_DIR>/scripts/validate-narrator.mjs
PR facts: ./capture/pr.json                          # title / body / commits / files / +/- stats — read first
Diff: ./capture/diff.patch                           # the actual change — pull 2-4 representative hunks
Brief: ./capture/extracted/visible-text.txt          # the assembled narrative brief
People: ./capture/extracted/people.json              # contributors (PR author + commit authors w/ commitCount + reviewers/commenters) + avatarFile; avatars in public/avatars/ — optional credits close
Design DNA: ./design-system/inference.json           # Read site_dna once to set register (soft hint only)
Orientation: <landscape | portrait | square>        # From the Step 0.0 aspect (16:9→landscape, 9:16→portrait, 1:1→square; default landscape). Emit VERBATIM as the top-level `orientation` field — dictated, not a choice; sets the canvas (portrait→1080×1920) for the whole pipeline.
Script style: concise, dev-facing — 1-2 sentences/scene, <=20 words; name the change, the why, the impact
The agent picks a PR archetype for
narrativeArchetype
(
changelog
/
feature-reveal
/
fix-explainer
/
refactor-walkthrough
, or
"<outer> with <inner>"
), echoes the dispatched
orientation
as a top-level field (Step 5 prep → canvas size), and emits
narrator_scripts.json
(it runs the validator before returning).
continuity
drives worker grouping:
continue
= same worker as the previous scene (cap=3);
break
= new worker; scene 1 is always
break
.
intent
/
sharedMotif
are soft hints.
assetCandidates
is
[]
on essentially every scene (faceless) — the one exception is an optional credits / shipped-by close that may reference the contributor avatars in
public/avatars/<login>.png
(from
people.json
).
调度一个子代理。提示词 =
agents/story-design.md
的完整内容 + 下方的
## Dispatch context
,原样传递:
SKILL_DIR: <绝对路径>
PROJECT_DIR: <视频项目根目录>
Schema验证器: <SKILL_DIR>/scripts/validate-narrator.mjs
PR信息: ./capture/pr.json                          # 标题/正文/提交/文件/增减行数统计——优先读取
差异: ./capture/diff.patch                           # 实际变更内容——提取2-4个代表性片段
简介: ./capture/extracted/visible-text.txt          # 组装后的叙事简介
人物: ./capture/extracted/people.json              # 贡献者(PR作者 + 提交作者及提交次数 + 审核者/评论者)+ avatarFile;头像位于public/avatars/——可选致谢结尾
设计特征: ./design-system/inference.json           # 读取site_dna一次以确定风格(仅软提示)
方向: <landscape | portrait | square>        # 来自步骤0.0的宽高比(16:9→landscape,9:16→portrait,1:1→square;默认landscape)。原样输出为顶级`orientation`字段——为指定值,不可选择;决定整个流程的画布尺寸(portrait→1080×1920)。
脚本风格: 简洁、面向开发者——每个场景1-2句话,≤20词;说明变更内容、原因及影响
代理为
narrativeArchetype
选择PR原型
changelog
/
feature-reveal
/
fix-explainer
/
refactor-walkthrough
,或
"<outer> with <inner>"
),将调度的**
orientation
原样作为顶级字段返回(步骤5预处理→画布尺寸),并输出
narrator_scripts.json
(返回前会运行验证器)。
continuity
控制工作进程分组:
continue
= 与上一场景使用同一工作进程(上限=3);
break
= 新工作进程;场景1始终为
break
intent
/
sharedMotif
为软提示。
assetCandidates
在几乎所有场景中均为
[]
(无人物出镜)——唯一例外是
可选的致谢/出品人结尾**,可能引用
public/avatars/<login>.png
中的贡献者头像(来自
people.json
)。

Step 3 - Audio — SHARED

步骤3 - 音频——共享

After
narrator_scripts.json
exists:
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/audio.mjs \
  --narrator-scripts ./narrator_scripts.json \
  --hyperframes . \
  --out ./audio_meta.json \
  --lyria-recipe <SKILL_DIR>/phases/audio/lyria-recipe.py)
BGM generation runs detached in the background. Backend selection (audio.mjs Step 5b): cloud Lyria is used only when a
GEMINI_API_KEY
/
GOOGLE_API_KEY
is set, the
--lyria-recipe
exists, AND
import google.genai
actually succeeds — if the key is set but the package is missing, audio.mjs tries to
pip install google-genai
on demand. When Lyria can't run, it falls back to local MusicGen (
facebook/musicgen-small
via transformers, no key; deps auto-installed in the background, parallel with TTS). BGM is only skipped entirely when neither backend can be made to run (e.g. no network for pip). It never blocks the render. Flags + BGM mechanics: top of
audio.mjs
.
  • exit 0 -> voice + transcribe complete (BGM may still be rendering;
    audio_meta.json
    records
    bgm_log
    /
    bgm_pid
    ), continue.
  • exit 1 -> zero scenes produced voice; report and stop.
narrator_scripts.json
生成后执行:
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/audio.mjs \
  --narrator-scripts ./narrator_scripts.json \
  --hyperframes . \
  --out ./audio_meta.json \
  --lyria-recipe <SKILL_DIR>/phases/audio/lyria-recipe.py)
背景音乐生成在后台独立运行。后端选择(audio.mjs步骤5b):云端Lyria仅在设置了
GEMINI_API_KEY
/
GOOGLE_API_KEY
、存在
--lyria-recipe
import google.genai
实际成功时使用——若设置了密钥但缺失依赖包,audio.mjs会尝试自动
pip install google-genai
。若Lyria无法运行,则降级为本地MusicGen(通过transformers使用
facebook/musicgen-small
,无需密钥;依赖包会在后台自动安装,与TTS并行执行)。仅当两个后端均无法运行时(例如无网络进行pip安装)才会完全跳过背景音乐生成。背景音乐生成不会阻塞渲染流程。标志位+背景音乐机制:详见audio.mjs顶部。
  • 退出码0 -> 语音+转录完成(背景音乐可能仍在渲染;
    audio_meta.json
    记录
    bgm_log
    /
    bgm_pid
    ),继续执行。
  • 退出码1 -> 无场景生成语音;上报并停止。

Step 4 - Visual-design (subagent) — SHARED

步骤4 - 视觉设计(子代理)——共享

After
design-system/chunks/index.json
,
narrator_scripts.json
, and
audio_meta.json
exist, concatenate all inputs into one dispatch packet (contracts first, static references middle, work items last):
bash
undefined
design-system/chunks/index.json
narrator_scripts.json
audio_meta.json
生成后,将所有输入拼接为一个调度包(先契约,再静态引用,最后工作项):
bash
undefined

Dispatch packets live in $PROJECT_DIR/.dispatch/ (transient; safe to delete after the run).

调度包存储在$PROJECT_DIR/.dispatch/(临时目录;运行完成后可安全删除)。

NEVER use a fixed /tmp path: it persists across runs/projects, so a failed write silently

切勿使用固定/tmp路径:该路径会跨运行/项目保留,写入失败会静默复用其他项目的陈旧包,污染所有工作进程。

reuses another project's stale packet and contaminates every worker.

mkdir -p "$PROJECT_DIR/.dispatch" DP="$PROJECT_DIR/.dispatch/vd-dispatch.txt" { echo "## Design chunks" (cd "$PROJECT_DIR" && cat design-system/chunks/index.json
design-system/chunks/composition-hints.md design-system/chunks/voice.md
design-system/chunks/tokens.css design-system/chunks/easings.js 2>/dev/null) echo "## Effects catalog"; cat <SKILL_DIR>/phases/visual-design/effects-catalog.md echo "## Design rules"; cat <SKILL_DIR>/phases/visual-design/rules/{typography,color-system,composition,motion-language}.md echo "## SFX library"; cat <SKILL_DIR>/assets/sfx/manifest.json echo "## Narrator scripts"; (cd "$PROJECT_DIR" && cat narrator_scripts.json) echo "## Audio meta"; (cd "$PROJECT_DIR" && cat audio_meta.json 2>/dev/null) # Optional; overrides Duration if drift >10% } > "$DP"
mkdir -p "$PROJECT_DIR/.dispatch" DP="$PROJECT_DIR/.dispatch/vd-dispatch.txt" { echo "## 设计代码块" (cd "$PROJECT_DIR" && cat design-system/chunks/index.json
design-system/chunks/composition-hints.md design-system/chunks/voice.md
design-system/chunks/tokens.css design-system/chunks/easings.js 2>/dev/null) echo "## 特效目录"; cat <SKILL_DIR>/phases/visual-design/effects-catalog.md echo "## 设计规则"; cat <SKILL_DIR>/phases/visual-design/rules/{typography,color-system,composition,motion-language}.md echo "## 音效库"; cat <SKILL_DIR>/assets/sfx/manifest.json echo "## 旁白脚本"; (cd "$PROJECT_DIR" && cat narrator_scripts.json) echo "## 音频元数据"; (cd "$PROJECT_DIR" && cat audio_meta.json 2>/dev/null) # 可选;若偏差>10%则覆盖时长 } > "$DP"

Guard: a partially-failed build must fail LOUDLY here, not downstream in the subagent

防护:部分失败的构建必须在此处明确失败,而非在子代理中出现问题

grep -q '^## Narrator scripts' "$DP" || { echo "FATAL: vd-dispatch.txt incomplete — rebuild before dispatching"; }
grep -q '^## 旁白脚本' "$DP" || { echo "致命错误:vd-dispatch.txt不完整——重新构建后再调度"; }

Captions planning hint (put it in the Captions: line of the dispatch below)

字幕规划提示(放入下方调度内容的Captions:行中)

(cd "$PROJECT_DIR" && node -e 'try{const m=require("./audio_meta.json");process.stdout.write(Object.values(m.scenes||{}).some(s=>s.wordsPath)?"enabled":"disabled")}catch{process.stdout.write("enabled")}')

Then dispatch the visual-design subagent. prompt = full contents of `agents/visual-design.md` + the `## Dispatch context` below, verbatim:
SKILL_DIR: <absolute path> PROJECT_DIR: <video project root> Schema validator: <SKILL_DIR>/scripts/validate-section.mjs Canvas: <width>×<height> # default 1920×1080 (16:9 landscape); 1080×1920 (9:16 portrait) or 1080×1080 (1:1 square) if requested upstream (narrator_scripts.orientation/dimensions). Plan layouts for THIS aspect ratio — see composition.md "Portrait & Square". Captions: <enabled | disabled> # Planning hint from the node -e above: enabled => leave the bottom ~17% of canvas height as caption territory in prose Dispatch packet: <PROJECT_DIR>/.dispatch/vd-dispatch.txt # Step 0 reads it once for all inputs Visuals: faceless code-change — every scene is a code-window / before-after split / file-tree / +/- counter / diagram / typography invented from the script + the featured diff hunk. assetCandidates is [] for most or all scenes; plan visuals from the script and diff, not from captured assets.

Output is `section_plan.md`. The `Captions:` line is an optimistic hint; the authoritative gate is `group_spec.captions_enabled` from Step 5.
(cd "$PROJECT_DIR" && node -e 'try{const m=require("./audio_meta.json");process.stdout.write(Object.values(m.scenes||{}).some(s=>s.wordsPath)?"enabled":"disabled")}catch{process.stdout.write("enabled")}')

然后调度视觉设计子代理。提示词 = `agents/visual-design.md`的完整内容 + 下方的`## Dispatch context`,原样传递:
SKILL_DIR: <绝对路径> PROJECT_DIR: <视频项目根目录> Schema验证器: <SKILL_DIR>/scripts/validate-section.mjs 画布: <width>×<height> # 默认1920×1080(16:9横屏);若上游请求(narrator_scripts.orientation/dimensions)则为1080×1920(9:16竖屏)或1080×1080(1:1正方形)。针对该宽高比规划布局——详见composition.md的"竖屏与正方形"章节。 字幕: <enabled | disabled> # 来自上述node -e的规划提示:enabled => 在文本场景中预留画布底部约17%的区域用于字幕 调度包: <PROJECT_DIR>/.dispatch/vd-dispatch.txt # 步骤0会一次性读取所有输入 视觉风格: 无人物出镜的代码变更——每个场景均为代码窗口/前后对比拆分/文件树/增减行数计数器/图表/根据脚本及重点差异片段生成的排版内容。assetCandidates在大多数或所有场景中均为[];根据脚本和差异规划视觉内容,而非采集的资产。

输出为`section_plan.md`。`Captions:`行是乐观提示;权威判断来自步骤5的`group_spec.captions_enabled`。

Step 5 - prep (deterministic script, NO subagent) — SHARED

步骤5 - 预处理(确定性脚本,不使用子代理)——共享

After
section_plan.md
exists:
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/prep.mjs \
  --section-plan ./section_plan.md \
  --narrator-scripts ./narrator_scripts.json \
  --audio-meta ./audio_meta.json \
  --rules-dir <SKILL_DIR>/../hyperframes-animation/rules \
  --capture ./capture \
  --design-system ./design-system \
  --hyperframes . \
  --sfx-lib <SKILL_DIR>/assets/sfx \
  --out ./group_spec.json)
Merges all upstream artifacts into
group_spec.json
(parse
section_plan
anchors, validate effect/component ids, group by
Continuity
with cap=3, build
visual_clips[]
where a multi-scene continue worker becomes one
group_wN.html
, compute Tier-B
transitions[]
between different visual clips, copy assets/fonts/SFX).
capture/assets/
is empty, so asset-copy is a no-op (faceless). Internal logic: header of
prep.mjs
.
--audio-meta ./audio_meta.json
is what carries each scene's
voicePath
/
wordsPath
and the
bgm_path
into
group_spec
— and therefore into the assembled
index.html
.
Omitting it (or pointing it at a path whose wavs don't resolve under
--hyperframes
) silently blanks every voice / caption / BGM track and renders a SILENT, caption-less video while every gate stays green. prep now defaults this flag to
./audio_meta.json
and prints a
CRITICAL
banner when
audio_meta
lists voiced scenes but none get wired;
assemble-index.mjs
re-asserts the same guard before render. Keep passing the flag explicitly anyway.
  • exit 0 -> read stdout (scenes / groups / total duration / per-group) and append to
    context.log
    .
  • exit 1 -> stderr names the failing scene + anchor (usually a malformed anchor or unknown effect/transition id); return to Step 4 and re-dispatch visual-design.
section_plan.md
生成后执行:
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/prep.mjs \
  --section-plan ./section_plan.md \
  --narrator-scripts ./narrator_scripts.json \
  --audio-meta ./audio_meta.json \
  --rules-dir <SKILL_DIR>/../hyperframes-animation/rules \
  --capture ./capture \
  --design-system ./design-system \
  --hyperframes . \
  --sfx-lib <SKILL_DIR>/assets/sfx \
  --out ./group_spec.json)
将所有上游产物合并为
group_spec.json
(解析
section_plan
锚点,验证特效/组件ID,按
Continuity
分组(上限=3),构建
visual_clips[]
(多场景连续工作进程合并为一个
group_wN.html
),计算不同视觉片段之间的Tier-B
transitions[]
,复制资产/字体/音效)。
capture/assets/
为空,因此资产复制为无操作(无人物出镜)。内部逻辑:详见prep.mjs头部。
--audio-meta ./audio_meta.json
用于将每个场景的
voicePath
/
wordsPath
bgm_path
传入
group_spec
——进而传入组装后的
index.html
若省略该参数(或指向的路径在
--hyperframes
下无法解析对应的wav文件),会静默清空所有语音/字幕/背景音乐轨道,渲染出无声、无字幕的视频,而所有检查仍显示正常。prep现在默认该标志为
./audio_meta.json
,当
audio_meta
列出有声场景但未正确连接时会打印
CRITICAL
横幅;
assemble-index.mjs
在渲染前会再次检查该防护。请始终显式传递该标志。
  • 退出码0 -> 读取stdout(场景/分组/总时长/每组时长)并追加至
    context.log
  • 退出码1 -> stderr会指出失败的场景+锚点(通常为格式错误的锚点或未知的特效/转场ID);返回步骤4重新调度视觉设计。

Step 5.5 + Step 6 - Captions (deterministic) + scene worker fan-out — SHARED

步骤5.5 + 步骤6 - 字幕(确定性)+ 场景工作进程分发——共享

Captions: two deterministic scripts (no subagent), after prep exits 0 and before fan-out:
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/captions.mjs group \
  --group-spec ./group_spec.json --hyperframes . \
  --tokens design-system/chunks/tokens.css --out ./caption_groups.json)

(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/captions.mjs html \
  --hyperframes . --groups ./caption_groups.json \
  --tokens design-system/chunks/tokens.css \
  --inference design-system/inference.json \
  --out compositions/captions.html)
exit 0 = normal. If either prints
captions: skipped (<reason>)
, skip the whole chain: no
captions.html
, assemble won't mount track 12. Skin selection / self-check: top of
captions.mjs html
(the claude preset ships its own
caption-skin.html
); for offline, pass
--skin-file
. Do not run
npx hyperframes lint
on
captions.html
.
Then ensure the overlap-gate dep once, from the workspace root (NOT inside
PROJECT_DIR
— the module must land in the workspace
node_modules/
where every worker and preflight can resolve it):
bash
node <SKILL_DIR>/scripts/check-overlap.mjs --ensure-deps
字幕:两个确定性脚本(不使用子代理),在prep退出码为0后、分发前执行:
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/captions.mjs group \
  --group-spec ./group_spec.json --hyperframes . \
  --tokens design-system/chunks/tokens.css --out ./caption_groups.json)

(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/captions.mjs html \
  --hyperframes . --groups ./caption_groups.json \
  --tokens design-system/chunks/tokens.css \
  --inference design-system/inference.json \
  --out compositions/captions.html)
退出码0 = 正常。若任一脚本打印
captions: skipped (<reason>)
,则跳过整个字幕流程:不生成
captions.html
,组装时不会挂载轨道12。皮肤选择/自检:详见captions.mjs html顶部(claude预设自带
caption-skin.html
);离线场景下可传递
--skin-file
请勿
captions.html
运行
npx hyperframes lint
然后从工作区根目录一次性确保重叠检查工具的依赖(不要
PROJECT_DIR
内执行——模块必须安装在工作区
node_modules/
中,以便所有工作进程和预检都能解析):
bash
node <SKILL_DIR>/scripts/check-overlap.mjs --ensure-deps

Installs puppeteer-core (module only, no browser download) if not already resolvable; Chrome is

若未解析到puppeteer-core则安装(仅模块,不下载浏览器);Chrome复用hyperframes浏览器缓存。

reused from the hyperframes browser cache. Workers must NOT install it themselves (parallel npm race).

工作进程不得自行安装(并行npm会导致竞争)。


Then read `group_spec.json.groups[]` for worker count N. Build the shared header once, then per-worker packets (`film direction` / `tokens` / `easings` / `voice` are identical for every worker):

```bash

然后读取`group_spec.json.groups[]`获取工作进程数量N。一次性构建共享头部,然后为每个工作进程生成包(`film direction`/`tokens`/`easings`/`voice`对所有工作进程相同):

```bash

Same rule as Step 4: packets go in $PROJECT_DIR/.dispatch/, never a fixed /tmp path

与步骤4相同规则:包存储在$PROJECT_DIR/.dispatch/,切勿使用固定/tmp路径

(a stale /tmp file from a previous project survives a failed write and silently

(之前项目的陈旧/tmp文件会在写入失败时静默复用,导致所有工作进程使用错误的设计系统)。

poisons every worker with the wrong design system).

mkdir -p "$PROJECT_DIR/.dispatch/scene-dispatch"
mkdir -p "$PROJECT_DIR/.dispatch/scene-dispatch"

## Film direction
= the film-level invariants from group_spec.film_direction

## 影片指导
= group_spec.film_direction中的影片级不变量

(palette system / motion defaults + budget / ambient system / negative list);

(调色板系统/运动默认值 + 预算/环境系统/禁用列表);

each scene's creative_brief carries only scene-specific deltas on top of it.

每个场景的creative_brief仅包含基于此的场景特定增量。

{ echo "## Film direction" (cd "$PROJECT_DIR" && node -p 'JSON.parse(require("fs").readFileSync("group_spec.json","utf8")).film_direction || ""') echo "## Tokens / easings / voice" (cd "$PROJECT_DIR" && cat design-system/chunks/tokens.css design-system/chunks/easings.js design-system/chunks/voice.md 2>/dev/null) } > "$PROJECT_DIR/.dispatch/scene-shared.txt"
{ echo "## 影片指导" (cd "$PROJECT_DIR" && node -p 'JSON.parse(require("fs").readFileSync("group_spec.json","utf8")).film_direction || ""') echo "## 令牌/缓动/语音" (cd "$PROJECT_DIR" && cat design-system/chunks/tokens.css design-system/chunks/easings.js design-system/chunks/voice.md 2>/dev/null) } > "$PROJECT_DIR/.dispatch/scene-shared.txt"

Guard BEFORE fan-out: the project's own brand token must be present; a contaminated

分发前防护:项目自身的品牌令牌必须存在;此处的包污染会导致所有受影响工作进程需要重新生成内容。

packet here costs a full re-author round across every affected worker.

grep -q -- '--brand-primary' "$PROJECT_DIR/.dispatch/scene-shared.txt" ||
{ echo "FATAL: scene-shared.txt incomplete/stale — rebuild before dispatching workers"; }
grep -q -- '--brand-primary' "$PROJECT_DIR/.dispatch/scene-shared.txt" ||
{ echo "致命错误:scene-shared.txt不完整/陈旧——重新构建后再调度工作进程"; }

Then per worker: shared header + that worker's Scenes YAML -> $PROJECT_DIR/.dispatch/scene-dispatch/w<N>.txt

然后为每个工作进程生成:共享头部 + 该工作进程的场景YAML -> $PROJECT_DIR/.dispatch/scene-dispatch/w<N>.txt


Start **N scene workers in parallel** (concurrent background dispatches; a harness concurrency cap below N means waves of the cap size until every worker has run — never fewer workers). prompt = full contents of `agents/hyperframes-scene.md` + `## Dispatch context`, verbatim. Top-level fields: `SKILL_DIR` / `PROJECT_DIR` / `Worker ID` / `Composition width` + `Composition height` (= `group_spec.width` / `group_spec.height`) / `Captions: <enabled|disabled>` (= `group_spec.captions_enabled`) / `Dispatch packet: <PROJECT_DIR>/.dispatch/scene-dispatch/w<N>.txt`, plus the shared header body (`## Film direction` + `## Tokens / easings / voice`) + a `Scenes:` list. Each worker's self-check runs two scoped machine gates before returning — `captions.mjs keepout --scene` (when captions enabled) and `check-overlap.mjs --scene` (always) — so layout violations are fixed at the source instead of surfacing at preflight.

For the worker top-level context, copy from `group_spec.json.groups[i]`: `worker_id`, `composition_id`, `composition_file`, `duration_s`, `scene_ids`; and from the top of `group_spec.json`: `width`, `height` (the worker authors + self-checks the root at these dims — landscape 1920×1080 unless portrait/square was requested upstream). **When `Captions: enabled`, also pass `Caption band top y` = `height − round(height × 0.1667)` and `Foreground max y` = `Caption band top y − 20`** (landscape → 900 / 880; portrait → 1600 / 1580) — constraint #13 keep-out is computed from these, not hardcoded. Copy every field in the **`Scenes:` list verbatim from `group_spec.json.groups[i].scenes[<sid>]`** (only that worker's 1-3 logical scenes): `scene_id` / `local_start_s` / `effects` / `rule_paths` / `assetCandidates` / `estimatedDuration_s` / `voicePath` / `design_chunks` (absolute paths to the whole component library — the worker chooses by visual judgment) / `creative_brief`. A continue run of 2-3 scenes writes one `group_wN.html` with true shared DOM across the segments.

`assetCandidates` is `[]` for most or all scenes — the worker invents the visual from `creative_brief` + design chunks (code-window for diffs, before/after, +/- counters); there are no captured assets to place. `design_chunks: null` (chunks missing) → worker falls back to reading `./design-system/design.html` fully; should not happen in the normal path.

After all workers + captions return, run preflight (scans `group_spec.visual_clips[]`; does NOT check `captions.html`):

```bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/check-compositions.mjs \
  --hyperframes . \
  --group-spec ./group_spec.json)
  • exit 0 -> all compositions pass, continue to Step 7.
  • exit 1 -> stderr names the violating scene + rule category; return to Step 6 and re-dispatch the affected worker (do not Edit in the master — fix upstream).

**并行启动N个场景工作进程**(后台并发调度;若执行环境并发上限低于N,则按上限分批执行,直到所有工作进程启动——不得减少工作进程数量)。提示词 = `agents/hyperframes-scene.md`的完整内容 + `## Dispatch context`,原样传递。顶级字段:`SKILL_DIR`/`PROJECT_DIR`/`Worker ID`/`Composition width`+`Composition height`(= `group_spec.width`/`group_spec.height`)/`Captions: <enabled|disabled>`(= `group_spec.captions_enabled`)/`Dispatch packet: <PROJECT_DIR>/.dispatch/scene-dispatch/w<N>.txt`,加上共享头部内容(`## 影片指导`+`## 令牌/缓动/语音`)+`Scenes:`列表。每个工作进程在返回前会运行两个范围化的机器检查——`captions.mjs keepout --scene`(字幕启用时)和`check-overlap.mjs --scene`(始终运行)——因此布局违规会在源头修复,而非在预检时暴露。

工作进程顶级上下文从`group_spec.json.groups[i]`复制:`worker_id`、`composition_id`、`composition_file`、`duration_s`、`scene_ids`;从`group_spec.json`顶部复制:`width`、`height`(工作进程按此尺寸创作+自检根元素——默认横屏1920×1080,除非上游请求竖屏/正方形)。**当`Captions: enabled`时,还需传递`Caption band top y` = `height − round(height × 0.1667)`和`Foreground max y` = `Caption band top y − 20`**(横屏→900/880;竖屏→1600/1580)——约束#13的禁区由此计算,而非硬编码。**`Scenes:`列表中的每个字段均原样从`group_spec.json.groups[i].scenes[<sid>]`复制**(仅该工作进程的1-3个逻辑场景):`scene_id`/`local_start_s`/`effects`/`rule_paths`/`assetCandidates`/`estimatedDuration_s`/`voicePath`/`design_chunks`(指向整个组件库的绝对路径——工作进程根据视觉判断选择)/`creative_brief`。连续运行的2-3个场景会写入一个`group_wN.html`,各片段共享同一DOM。

`assetCandidates`在大多数或所有场景中均为[]——工作进程根据`creative_brief`+设计代码块生成视觉内容(差异用代码窗口、前后对比、增减行数计数器);无采集资产可使用。`design_chunks: null`(代码块缺失)→ 工作进程回退为完整读取`./design-system/design.html`;正常流程中不应出现此情况。

所有工作进程+字幕流程完成后,执行预检(扫描`group_spec.visual_clips[]`;不检查`captions.html`):

```bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/check-compositions.mjs \
  --hyperframes . \
  --group-spec ./group_spec.json)
  • 退出码0 -> 所有合成内容通过检查,进入步骤7。
  • 退出码1 -> stderr会指出违规场景+规则类别;返回步骤6重新调度受影响的工作进程(不要在主进程中编辑——在上游修复)。

Step 7 - Assembly prelude + preflight gate + finalize — SHARED

步骤7 - 组装前置流程 + 预检关卡 + 最终处理——共享

After Step 6 exits 0: a deterministic Bash prelude (wait-bgm + assemble + inject/verify-transitions + hoist-videos + sfx-verify + preflight), then one finalize subagent that fixes the brief's findings in place, takes ONE lean contact-sheet look, and renders. Principle: deterministic prelude is all Bash; findings go to finalize (not back to workers); worker re-dispatch is reserved for recomposition.
compositions/scene_N.html
/
group_wN.html
are worker source files; editing them edits the source.
(1) BGM wait + assembly (Bash):
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/wait-bgm.mjs \
  --audio-meta ./audio_meta.json \
  --hyperframes . \
  --timeout-ms 120000 \
  --interval-ms 2000)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/assemble-index.mjs --group-spec ./group_spec.json --hyperframes .)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/transitions.mjs inject --group-spec ./group_spec.json --hyperframes .)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/transitions.mjs verify --group-spec ./group_spec.json --index ./index.html)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/hoist-videos.mjs --group-spec ./group_spec.json --hyperframes .)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/verify-output.mjs sfx --group-spec ./group_spec.json --index ./index.html)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/verify-output.mjs audio --hyperframes . --group-spec ./group_spec.json --index ./index.html)
inject
only changes the
index.html
shell
data-start
/
data-duration
/
data-track-index
, never visual roots.
hoist-videos
reads each scene's poster
data-video-src
declarations, measures the poster's rendered rect headless, and mounts the real
<video class="clip">
at the index.html host root with global timing clamped clear of transitions
— the ONLY legal way footage plays, since the runtime never decodes a
<video>
nested in a scene. Internal logic: header of each script.
  • assemble exit 1 -> names a visual composition (root
    data-duration
    != group_spec, or file missing) = worker contract break → return to Step 6, re-dispatch that worker, rerun this step.
  • inject/verify-transitions exit 1 -> injector bug (prep already validated
    transitions[]
    ) → report, don't roll back workers.
  • hoist-videos exit 1 -> a
    data-video-src
    declaration is invalid (missing file / bad numbers / window too small after transition clamping / poster not measurable) — stderr names the scene + declaration;
    Edit
    the visual source file (or re-dispatch its worker for a real relayout), then rerun this step. exit 2 -> browser unavailable; run
    node <SKILL_DIR>/scripts/check-overlap.mjs --ensure-deps
    from the workspace root, then rerun. exit 0 prints one line per hoisted video (src, global window, track, rect).
  • sfx-verify exit 1 -> assembler bug → report.
  • verify-output audio exit 1 -> a voice wav /
    bgm.wav
    /
    captions.html
    exists on disk but was NOT wired into
    index.html
    (the silent / caption-less render class). This is an upstream wiring bug — almost always empty
    group_spec
    voicePaths because prep ran without
    --audio-meta
    . Do NOT render. Re-run Step 5 prep with
    --audio-meta ./audio_meta.json
    , then re-run this Step 7(1) chain.
    -prefixed lines (BGM / captions intended but never produced on disk) are non-blocking generation gaps — render proceeds.
(2) Preflight gate (Bash):
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/preflight-finalize.mjs --group-spec ./group_spec.json --hyperframes .)
preflight does everything the agent does not need to judge and writes it all into
finalize_brief.json
: warms a pinned
npx hyperframes@<version>
cache, runs lint/validate/inspect with that version (inspect runs STRICT — no
--tolerance
flag, CLI default
; by-design transient overflow from 3D morph / tilt / zoom peaks is declared per-element with
data-layout-allow-overflow
, never absorbed numerically — any re-run of inspect elsewhere must also be plain or verdicts disagree) and captures tails + summary counts, computes the snapshot timeline, runs
check-overlap.mjs
(the single-rule rendered overlap gate: every scene loaded headless, timeline seeked to 0.4/0.7/0.92 of duration, all non-background paint atoms flattened onto one plane with z-index ignored, pairwise-intersected; persistent overlap = a finding finalize must fix;
status: unavailable
blocks at exit 2 — the gate never soft-skips), and when
captions_enabled
runs
captions.mjs keepout
static check for "foreground lower edge y <= 900" (the bbox math folds in CSS transforms AND
margin-top
/
margin-bottom
, so negative-margin-centered cards are measured at their real bbox). Keep-out violations include ready-to-apply Edit strings (
edit_old
/
edit_new
) and overlap violations carry both selectors + both rects + the overlap rect — finalize consumes both directly and fixes them in place. Brief fields (
preflight_clean
/
gates_clean
/
gates.*
/
bgm.*
/
overlap.*
/
caption_keepout.*
/
anomalies[]
/
snapshot_times_s[]
/
npx_prefix
/
scenes[]
/
internal_seams[]
) and algorithm details are documented at the top of
preflight-finalize.mjs
. Only contrast and cramped-container remain eye-owned (finalize's one contact-sheet scan); collision / panel-bleed are machine-owned by the overlap gate.
  • exit 0 -> dispatch finalize — clean or not. Findings (gate errors /
    overlap.violations[]
    /
    caption_keepout.violations[]
    ) ride in the brief and finalize fixes them in place as its first work step. Do NOT diagnose them yourself, do NOT hand-Edit scene files, do NOT re-dispatch workers for them.
  • exit 2 -> ONLY when the overlap gate could not run (
    overlap.status: "unavailable"
    — puppeteer-core / Chrome missing). Environment problem with a deterministic remedy: run
    node <SKILL_DIR>/scripts/check-overlap.mjs --ensure-deps
    from the workspace root (and
    npx hyperframes doctor
    if it names Chrome), then rerun preflight — do not proceed unmeasured.
  • exit 1 -> preflight itself crashed (bad invocation / missing group_spec) → fix the invocation.
Worker re-dispatch (Repair Mode) is the EXCEPTION path now, not a preflight branch: it triggers only when finalize STOPs because a scene needs recomposition (content fundamentally wrong / real relayout / animation broken beyond a couple of edits). Then: re-dispatch that scene's owning worker (a continue worker owns its whole
group_wN.html
and repairs all its logical scenes together) with the full
agents/hyperframes-scene.md
+ the normal dispatch context + a
## Repair context
block containing: (a) finalize's verbatim findings for that worker's scene(s) (never paraphrase measurements), (b)
npx_prefix
copied from
finalize_brief.json
, (c)
Inspect at: <t1,t2,t3>
= that scene's
midpoint_s
+
high_risk_extras_s
(or
start_s + 0.5/0.75/0.9 × duration
) from
brief.scenes[]
, (d)
Captions: enabled|disabled
. Per the contract's Repair Mode section, each worker Edits in place and self-verifies (scoped plain
inspect --at
+
check-overlap.mjs --scene
+ keepout) before returning
— so you (master) do NOT hand-Edit scene files and do NOT re-run the full preflight after each individual fix. When ALL repair workers have returned green, rerun (1)+(2) once and re-dispatch finalize. If the same finding survives two full repair rounds, STOP and surface it to the user instead of looping.
Scan
anomalies[]
even on exit 0 (loud non-blocking warnings surfaced by preflight; currently rare — read each entry's
message
and decide whether it changes the dispatch).
(3) Dispatch finalize subagent (fix brief findings in place -> ONE lean contact-sheet look -> render). prompt = full contents of
agents/hyperframes-finalize.md
+
## Dispatch context
:
SKILL_DIR: <absolute path>
PROJECT_DIR: <video project root>
Render quality: high     # Or draft / standard
Finalize brief: <PROJECT_DIR>/finalize_brief.json   # Preflight has already written it; agent reads once for findings + npx_prefix + scene timings
Film direction: |        # = group_spec.film_direction (film-level invariants the briefs assume)
  <verbatim>
Visual clips:            # One line per group_spec.visual_clips[] entry
  - { id, file, kind, worker_id, scene_ids, start_s, duration_s }
Scenes:                  # One line per logical scene, copied verbatim from group_spec.json
  - { scene_id, start_s, estimatedDuration_s, effects: [...], creative_brief: |
      <Phase 3 prose for this scene> }
index.html
is already assembled (transitions injected, videos hoisted); all gates have already run. Finalize's flow: fix every brief finding in place first (gate
output_tail
-> Edit + rerun only that gate;
overlap.violations[]
-> Edit per the given selectors/rects + scoped
check-overlap --scene
verify;
caption_keepout.violations[]
-> apply
edit_old
/
edit_new
mechanically), then ONE snapshot call at scene midpoints + group-internal continue-seam mids, one read of the contact sheet (looking only for blank/black panels, cut or unreadable text, crushed interiors, seam jank — escalate single frames only on suspicion), then render + verify-render. No per-frame QA walkthrough. Finalize must never change a visual root
data-duration
(=
visual_clips[].duration_s
, fixed upstream; changing it makes assemble fatal — timing is only fixable by returning to Step 6).
  • finalize reports the mp4 (verify-render passed) + gate/snapshot status + files repaired in place -> complete.
  • finalize STOP (only when a scene needs full recomposition) -> return to Step 6, re-dispatch that worker, rerun (1)+(2), re-dispatch finalize.
步骤6退出码为0后:执行确定性Bash前置流程(等待背景音乐 + 组装 + 注入/验证转场 + 提升视频层级 + 音效验证 + 预检),然后启动一个最终处理子代理,修复预检发现的问题,生成一张精简预览图,然后渲染。原则:确定性前置流程全部使用Bash;问题交由最终处理子代理(不返回给工作进程);工作进程重新调度仅用于重新合成内容。
compositions/scene_N.html
/
group_wN.html
为工作进程源文件;编辑这些文件即编辑源内容。
(1) 等待背景音乐 + 组装(Bash):
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/wait-bgm.mjs \
  --audio-meta ./audio_meta.json \
  --hyperframes . \
  --timeout-ms 120000 \
  --interval-ms 2000)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/assemble-index.mjs --group-spec ./group_spec.json --hyperframes .)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/transitions.mjs inject --group-spec ./group_spec.json --hyperframes .)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/transitions.mjs verify --group-spec ./group_spec.json --index ./index.html)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/hoist-videos.mjs --group-spec ./group_spec.json --hyperframes .)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/verify-output.mjs sfx --group-spec ./group_spec.json --index ./index.html)
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/verify-output.mjs audio --hyperframes . --group-spec ./group_spec.json --index ./index.html)
inject
仅修改
index.html
外壳的
data-start
/
data-duration
/
data-track-index
,从不修改视觉根元素。
hoist-videos
读取每个场景的海报
data-video-src
声明,通过无头浏览器测量海报的渲染矩形,然后在index.html宿主根元素挂载真实的
<video class="clip">
,并根据转场调整全局时间——这是视频播放的唯一合法方式,因为运行时不会解码嵌套在场景中的
<video>
。内部逻辑:详见每个脚本的头部。
  • 组装退出码1 -> 指出某个视觉合成内容(根元素
    data-duration
    与group_spec不符,或文件缺失)= 工作进程违反契约 → 返回步骤6,重新调度该工作进程,重新执行此步骤。
  • 注入/验证转场退出码1 -> 注入器bug(prep已验证
    transitions[]
    )→ 上报,不要回滚工作进程。
  • hoist-videos退出码1 ->
    data-video-src
    声明无效(文件缺失/数值错误/转场调整后窗口过小/无法测量海报)——stderr会指出场景+声明;编辑视觉源文件(或重新调度其工作进程进行真实重布局),然后重新执行此步骤。退出码2 -> 浏览器不可用;从工作区根目录执行
    node <SKILL_DIR>/scripts/check-overlap.mjs --ensure-deps
    ,然后重新执行此步骤。退出码0会打印每个提升视频的信息(源、全局时间窗口、轨道、矩形)。
  • 音效验证退出码1 -> 组装器bug → 上报。
  • 验证输出音频退出码1 -> 语音wav/
    bgm.wav
    /
    captions.html
    存在于磁盘但未连接到
    index.html
    (无声/无字幕渲染情况)。这是上游连接bug——几乎总是因为prep运行时未传入
    --audio-meta
    导致
    group_spec
    的voicePaths为空。请勿渲染。重新运行步骤5的prep并传入
    --audio-meta ./audio_meta.json
    ,然后重新执行步骤7(1)流程。以
    开头的行(预期生成背景音乐/字幕但未在磁盘生成)为非阻塞生成缺口——渲染仍可继续。
(2) 预检关卡(Bash):
bash
(cd "$PROJECT_DIR" && node <SKILL_DIR>/scripts/preflight-finalize.mjs --group-spec ./group_spec.json --hyperframes .)
预检执行所有无需人工判断的检查,并将结果写入
finalize_brief.json
:预热固定版本的
npx hyperframes@<version>
缓存,使用该版本运行lint/validate/inspect(inspect严格运行——无
--tolerance
标志,使用CLI默认值
;3D变形/倾斜/缩放峰值导致的设计内临时溢出需通过
data-layout-allow-overflow
逐个元素声明,不得数值吸收——其他地方重新运行inspect必须使用相同方式,否则判断结果会不一致)并捕获尾部信息+统计摘要,计算快照时间线,运行**
check-overlap.mjs
**(单一规则的渲染重叠检查:通过无头浏览器加载每个场景,将时间线定位到时长的0.4/0.7/0.92处,忽略z-index将所有非背景绘制元素展平到同一平面,两两相交;持续重叠=需最终处理子代理修复的问题;
status: unavailable
会以退出码2阻塞——检查关卡从不软跳过),当
captions_enabled
时运行
captions.mjs keepout
静态检查“前景下边缘y <= 900”(边界框计算包含CSS变换及
margin-top
/
margin-bottom
,因此负边距居中的卡片会按真实边界框测量)。禁区违规包含可直接应用的编辑字符串
edit_old
/
edit_new
),重叠违规包含选择器+矩形+重叠矩形——最终处理子代理直接使用这些信息进行修复。简介字段(
preflight_clean
/
gates_clean
/
gates.*
/
bgm.*
/
overlap.*
/
caption_keepout.*
/
anomalies[]
/
snapshot_times_s[]
/
npx_prefix
/
scenes[]
/
internal_seams[]
)及算法细节详见preflight-finalize.mjs顶部。仅对比度和容器拥挤问题需人工判断(最终处理子代理的一次预览图扫描);碰撞/面板溢出由重叠检查关卡自动处理。
  • 退出码0 -> 调度最终处理子代理——无论是否存在问题。问题(关卡错误/
    overlap.violations[]
    /
    caption_keepout.violations[]
    )会随简介传递,最终处理子代理会在第一步就地修复。请勿自行诊断,请勿手动编辑场景文件,请勿因这些问题重新调度工作进程。
  • 退出码2 -> 仅当重叠检查关卡无法运行时(
    overlap.status: "unavailable"
    ——缺失puppeteer-core/Chrome)。环境问题有确定性解决方案:从工作区根目录执行
    node <SKILL_DIR>/scripts/check-overlap.mjs --ensure-deps
    (若提示Chrome缺失则执行
    npx hyperframes doctor
    ),然后重新执行预检——不得在未测量的情况下继续。
  • 退出码1 -> 预检自身崩溃(调用方式错误/缺失group_spec)→ 修复调用方式。
工作进程重新调度(修复模式)为异常流程,而非预检分支:仅当最终处理子代理停止时触发,原因是场景需要重新合成(内容根本错误/真实重布局/动画损坏无法通过少量编辑修复)。此时:重新调度该场景的所属工作进程(连续工作进程负责其整个
group_wN.html
并一起修复所有逻辑场景),传入完整的
agents/hyperframes-scene.md
+正常调度上下文+
## Repair context
块,包含:(a) 最终处理子代理针对该工作进程场景的原样问题描述(不得转述测量值),(b) 从
finalize_brief.json
复制的
npx_prefix
,(c)
Inspect at: <t1,t2,t3>
= 该场景的
midpoint_s
+
high_risk_extras_s
(或
start_s + 0.5/0.75/0.9 × duration
),来自
brief.scenes[]
,(d)
Captions: enabled|disabled
。根据契约的修复模式章节,每个工作进程就地编辑并自检(范围化的普通
inspect --at
+
check-overlap.mjs --scene
+禁区检查)后返回
——因此你(主进程)不得手动编辑场景文件,也不得在每次修复后重新运行完整预检。当所有修复工作进程返回成功后,重新执行(1)+(2)一次,然后重新调度最终处理子代理。若同一问题在两次完整修复后仍存在,请停止并向用户反馈,不要循环。
即使退出码为0,也请扫描
anomalies[]
(预检发现的明显非阻塞警告;目前很少见——阅读每个条目的
message
并决定是否调整调度)。
(3) 调度最终处理子代理(就地修复简介问题 -> 生成一张精简预览图 -> 渲染)。提示词 =
agents/hyperframes-finalize.md
的完整内容 +
## Dispatch context
SKILL_DIR: <绝对路径>
PROJECT_DIR: <视频项目根目录>
渲染质量: high     # 或draft / standard
最终处理简介: <PROJECT_DIR>/finalize_brief.json   # 预检已写入该文件;代理读取一次获取问题+npx_prefix+场景时间线
影片指导: |        # = group_spec.film_direction(简介假设的影片级不变量)
  <原样内容>
视觉片段:            # 每个group_spec.visual_clips[]条目一行
  - { id, file, kind, worker_id, scene_ids, start_s, duration_s }
场景:                  # 每个逻辑场景一行,原样从group_spec.json复制
  - { scene_id, start_s, estimatedDuration_s, effects: [...], creative_brief: |
      <阶段3的该场景描述> }
index.html
已组装完成(转场已注入,视频已提升层级);所有检查关卡已运行。最终处理流程:首先就地修复所有简介问题(关卡
output_tail
-> 编辑+仅重新运行该关卡;
overlap.violations[]
-> 根据给定选择器/矩形编辑+范围化
check-overlap --scene
验证;
caption_keepout.violations[]
-> 机械应用
edit_old
/
edit_new
),然后在场景中点+组内连续接缝中点生成一次快照,读取预览图(仅检查空白/黑色面板、截断或不可读文本、挤压内部、接缝抖动——仅在怀疑时上报单帧),然后渲染+验证渲染结果。无需逐帧QA检查。最终处理子代理不得修改视觉根元素的
data-duration
(=
visual_clips[].duration_s
,由上游固定;修改会导致组装失败——时间仅能通过返回步骤6修复)。
  • 最终处理子代理上报mp4(验证渲染通过)+ 关卡/快照状态+就地修复的文件 -> 完成。
  • 最终处理子代理停止(仅当场景需要完全重新合成时)-> 返回步骤6,重新调度该工作进程,重新执行(1)+(2),重新调度最终处理子代理。

Completion report

完成报告

Summarize per phase: PR (repo / #N / title), preset (always
claude
), PR archetype, scene count / total duration, worker grouping, transitions, gate status (lint / validate / inspect (strict) / overlap), hoisted videos (count + tracks), findings fixed in place, lean pass (tiles scanned, escalations), visual files repaired in place, final mp4 path + bytes + duration.
Offer a live preview — never auto-open one. The deliverable is the mp4 above. A browser preview is optional and must not be started until the user asks for it. Do NOT run
hyperframes preview
/
play
during any earlier phase: a preview opened mid-run shows half-edited compositions and dies when that phase's own snapshot/render server is torn down. When the user asks, start a long-lived dev server after the render (it serves the final on-disk files and stays up until stopped), then report the actual URL with the real port + project name:
bash
(cd "$PROJECT_DIR" && npx hyperframes preview)   # Studio UI, e.g. http://localhost:3002/#project/<project-name>
按阶段总结:PR(仓库/#N/标题)、预设(始终为
claude
)、PR原型、场景数量/总时长、工作进程分组、转场、关卡状态(lint/validate/inspect(严格)/overlap)、提升的视频(数量+轨道)、就地修复的问题、精简检查(扫描的预览图块、上报问题)、就地修复的视觉文件、最终mp4路径+大小+时长。
提供在线预览——切勿自动打开。交付物为上述mp4文件。浏览器预览为可选功能,必须在用户请求后再启动。请勿在任何早期阶段运行
hyperframes preview
/
play
:中途打开的预览会显示半编辑的合成内容,且会在该阶段的快照/渲染服务器关闭时崩溃。当用户请求时,在渲染完成后启动长期开发服务器(提供最终磁盘文件,直到停止),然后上报真实URL+端口+项目名称:
bash
(cd "$PROJECT_DIR" && npx hyperframes preview)   # Studio UI,例如http://localhost:3002/#project/<project-name>

or a lightweight shareable player link instead:

或使用轻量可分享播放器链接:

(cd "$PROJECT_DIR" && npx hyperframes play) # plain http://localhost:<port>

Flags (custom port, external browser) live in the `hyperframes-cli` skill (`references/preview-render.md`).

---
(cd "$PROJECT_DIR" && npx hyperframes play) # 普通http://localhost:<port>

标志位(自定义端口、外部浏览器)详见`hyperframes-cli`工具(`references/preview-render.md`)。

---

Resume table

恢复表

Read
$PROJECT_DIR/context.log
and resume from:
StateContinue from
log missing or emptyFull pipeline
capture/pr.json
or
capture/extracted/visible-text.txt
missing
Step 1 (ingest)
ingest done,
design-system/inference.json
or
chunks/index.json
missing
Step 1b (three deterministic commands)
chunks/index.json
exists,
narrator_scripts.json
missing
Step 2 (story-design). If the user supplied a final
narrator_scripts.json
, place it in
$PROJECT_DIR/
to skip this state
narrator_scripts.json
exists,
audio_meta.json
missing
Step 3 (audio)
audio_meta.json
exists,
section_plan.md
missing
Step 4 (visual-design)
section_plan.md
exists,
group_spec.json
missing
Step 5 (prep)
group_spec.json
exists, any
visual_clips[].file
missing or
caption_groups.json
missing
Step 5.5+6 (run
captions.mjs group
->
html
, then dispatch workers for missing clips). Captions-ran criterion =
caption_groups.json
exists (NOT
captions.html
)
all
visual_clips[].file
exist + captions decided,
renders/video.mp4
missing
Step 7 (rerun assemble + sfx-verify + preflight, overwriting
finalize_brief.json
/
index.html
, then dispatch finalize)
renders/video.mp4
exists
Report completed and stop
读取
$PROJECT_DIR/context.log
并从以下状态恢复:
状态恢复起点
日志缺失或为空完整流水线
capture/pr.json
capture/extracted/visible-text.txt
缺失
步骤1(采集)
采集完成,
design-system/inference.json
chunks/index.json
缺失
步骤1b(三个确定性命令)
chunks/index.json
存在,
narrator_scripts.json
缺失
步骤2(故事设计)。若用户提供了最终的
narrator_scripts.json
,将其放入
$PROJECT_DIR/
以跳过此状态
narrator_scripts.json
存在,
audio_meta.json
缺失
步骤3(音频)
audio_meta.json
存在,
section_plan.md
缺失
步骤4(视觉设计)
section_plan.md
存在,
group_spec.json
缺失
步骤5(预处理)
group_spec.json
存在,任一
visual_clips[].file
缺失
caption_groups.json
缺失
步骤5.5+6(运行
captions.mjs group
->
html
,然后调度缺失片段的工作进程)。字幕已运行的判断标准为
caption_groups.json
存在(而非
captions.html
所有
visual_clips[].file
存在+字幕已确定,
renders/video.mp4
缺失
步骤7(重新运行组装+音效验证+预检,覆盖
finalize_brief.json
/
index.html
,然后调度最终处理子代理)
renders/video.mp4
存在
上报完成并停止

Directory shape

目录结构

text
./                            # workspace root
├── .claude/skills/
├── node_modules/  package.json
└── videos/<project-name>/    # PROJECT_DIR - HyperFrames project root
    ├── hyperframes.json  context.log
    ├── capture/              # synthetic package (NOT a scrape) — kept for backend layout compatibility
    │   ├── pr.json           # gh pr view --json (now incl. reviews / comments / assignees / reviewDecision)
    │   ├── diff.patch        # gh pr diff (the full change; story-design pulls hunks from here)
    │   ├── extracted/        # tokens.json (synthetic) + visible-text.txt (brief) + people.json (contributors)
    │   └── assets/           # empty (faceless)
    ├── design-system/        # build-design outputs: inference.json / design.html / chunks/ / fonts/
    ├── narrator_scripts.json  audio_meta.json  section_plan.md  group_spec.json
    ├── public/  assets/  compositions/  snapshots/   # public/avatars/<login>.png — contributor avatars
    └── renders/video.mp4
text
./                            # 工作区根目录
├── .claude/skills/
├── node_modules/  package.json
└── videos/<project-name>/    # PROJECT_DIR - HyperFrames项目根目录
    ├── hyperframes.json  context.log
    ├── capture/              # 合成包(非抓取内容)——为兼容后端布局保留
    │   ├── pr.json           # gh pr view --json(现包含reviews/comments/assignees/reviewDecision)
    │   ├── diff.patch        # gh pr diff(完整变更内容;故事设计从此处提取片段)
    │   ├── extracted/        # tokens.json(合成) + visible-text.txt(简介) + people.json(贡献者)
    │   └── assets/           # 空(无人物出镜)
    ├── design-system/        # build-design输出:inference.json / design.html / chunks/ / fonts/
    ├── narrator_scripts.json  audio_meta.json  section_plan.md  group_spec.json
    ├── public/  assets/  compositions/  snapshots/   # public/avatars/<login>.png ——贡献者头像
    └── renders/video.mp4

Routing note (for the hyperframes-read-first router)

路由说明(供hyperframes-read-first路由器使用)

  • Input: a GitHub PR — a code change (PR URL,
    owner/repo#N
    , or "this PR"). A URL, but a
    github.com/.../pull/N
    link, not a product/marketing website
    .
  • Output: code-change explainer, up to ~3 min (sweet spot ~30-90s); 5 min+ exhaustive deep-dives →
    /general-video
    .
  • Triggers: "make a video about this PR", "turn PR #1187 into a changelog video", "explain what this pull request does as a video", "release-notes video from github.com/org/repo/pull/123", "turn this PR into a video".
  • Do NOT use for: a product/marketing website URL (->
    /product-launch-video
    ) or a general website to turn into a video (->
    /website-to-video
    ); a topic/article/text with no PR (->
    /faceless-explainer
    ); adding captions to an existing video (->
    /embedded-captions
    ); a whole-repo tour or multi-PR release (no workflow yet ->
    /general-video
    ).
  • 输入: GitHub PR——代码变更(PR URL、
    owner/repo#N
    或“this PR”)。虽为URL,但必须是
    github.com/.../pull/N
    链接,而非产品/营销网站。
  • 输出: 代码变更讲解视频,最长约3分钟(最佳时长30-90秒);5分钟以上的详尽深度讲解请使用
    /general-video
  • 触发词: "make a video about this PR", "turn PR #1187 into a changelog video", "explain what this pull request does as a video", "release-notes video from github.com/org/repo/pull/123", "turn this PR into a video"。
  • 请勿用于: 产品/营销网站URL(->
    /product-launch-video
    )或需转换为视频的通用网站(->
    /website-to-video
    );无PR的主题/文章/文本(->
    /faceless-explainer
    );为现有视频添加字幕(->
    /embedded-captions
    );全仓库漫游或多PR版本发布(暂无对应工作流 ->
    /general-video
    )。