Frame N — Title
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
解析器接受 `Frame` / `Beat` / `Scene` 三种关键词作为小节标记,且允许出现在 **H2 或 H3** 层级(见 [FRAME_HEADING_RE](https://link.gitcode.com/i/de90c94f27582fdd9fccefd28c9d4654))。帧号 `N` 既可以是普通整数(如 `3`),也支持 `1.1` 这类编号(`parseHeading` 会提取前导整数)。 每个帧小节的构成如下: - 标题下方是元数据行,格式为 `- key: value`(也接受 `* key: value`,见 [META_RE](https://link.gitcode.com/i/22895477b3b23b88db09060ec2926c23)); - 元数据下方直到下一个同层或更浅层标题之间的内容,是自由形式的**叙事**(narrative)文本。 ```markdown ## Frame 1 — Hook - scene: Big type punches in on the beat - duration: 3s - poster: 2s - transition_in: cut - status: animated - voiceover: "Ship a launch video in an afternoon." - src: compositions/frames/01-hook.html Open cold on the promise. This is the thesis — everything after pays it off.已知元数据键
| 键 | 含义 |
|---|---|
status | outline→built→animated(默认outline) |
src | 指向该帧 HTML 子合成的项目相对路径(contact-sheet 缩略图由此渲染) |
duration | 例如4s |
transition_in | 入场转场:crossfade/cut/wipe…(别名transition) |
scene | 一行式 contact-sheet 图注(别名description/summary/caption) |
voiceover | 该帧的旁白指引(别名vo/voice_over/narration) |
poster | 用于生成缩略图的定位秒数(需跳过开场动画) |
| 其他任意键 | 原样保留在帧的extra下——工作流可在此携带自己的逐帧数据(特效、素材等) |
别名的源码实现
这些别名并非文档层面的"建议",而是解析器的硬编码映射:
- 转场键集合
TRANSITION_KEYS = {"transition_in", "transitionin", "transition"}; - 场景键集合
SCENE_KEYS = {"scene", "description", "summary", "caption"}; - 旁白别名
VOICEOVER_ALIASES = ["voiceover", "vo", "voice_over", "narration"]——定义在 parseStoryboard.ts,并被 editStoryboard.ts 导入复用,确保读、写两侧对字段名的理解永远一致、不会漂移。
关键解析细节(可从源码确认)
status规范化:解析器会将值转为小写并与FRAME_STATUSES(["outline", "built", "animated"])比对(applyStatus)。若出现未知状态值,不会报错,而是把原值塞进frame.extra.status并记录一条 warning,同时回退到默认状态outline。duration解析:applyDuration同时保留原始字符串(duration)和解析出的数值秒数(durationSeconds);当无法从中提取数字时会记录 warning,但不会中断解析。voiceover与引号:旁白值会经过stripQuotes,剥掉最外层的一对"或'。poster解析:同样用数字正则提取数值,得到秒数。- 未知元数据键一律落入
frame.extra,逐字保留——这是工作流携带自有数据的官方通道。
帧生命周期的三种状态
outline → built → animated是每帧的生命周期,Studio 会依据它渲染进度:
outline:仅计划,尚无实际 HTML。status: outline且没有src的帧在 contact sheet 中渲染为轮廓占位符(outline placeholder);built:中间档——帧的 HTML 已存在且布局已确认(至少是线框草图级别),但动画尚未添加,Studio 用蓝色 chip 标记该状态;animated:完成动画。
驱动这些状态流转的过程(计划 → 草图 → 构建,每轮都在板上评审)见 review-loop.md。
四、解析后的 Manifest:StoryboardManifest
解析器 parseStoryboard 的核心设计原则是宽松(lenient):它从不抛异常,任何意外内容都记录为warning。完整的类型定义在 types.ts:
StoryboardManifest { globals: { format?, message?, arc?, audience?, extra: {…} } frames: Array<{ index, number?, title?, status, // "outline" | "built" | "animated" src?, duration? / durationSeconds?, transitionIn?, scene?, voiceover?, poster?, narrative, // metadata 下方的 markdown extra: {…} // 未知键,原样保留 }> warnings: Array<{ message, line?, frameIndex? }> }值得注意的字段语义(均与源码一一对应):
index:1 基序号,按文档顺序分配,与作者写的Frame N中的number相互独立;number/title:从标题文本中拆解出的帧号与标题;narrative:元数据行之下的自由 Markdown 正文,解析器不做任何结构假设;warnings:解析过程中遇到的非致命问题(未知状态、无法解析的时长、未闭合的 Frontmatter 等),每条可携带 1 基的行号与帧号,方便定位;globals/frames的extra:分别是 Frontmatter 与帧元数据中未知键的逐字保留区。
读取 API 的增量字段
GET /api/projects/<id>/storyboard返回的 JSON 会在 Manifest 基础上增加两层信息(storyboard.ts):
srcExists(逐帧):路由会用resolveWithinProject将src解析为项目内的绝对路径并检查文件是否存在,供 Studio 判断缩略图能否渲染;SCRIPT.md载荷:当项目根目录存在可选的SCRIPT.md时,以script: { exists, path, content }形式一并返回。
此外,当项目里根本没有STORYBOARD.md时,API不会返回 404,而是返回exists: false、空帧数组,让 Studio 可以渲染一个可选的空状态(opt-in),而不是报错。
五、SCRIPT.md:锁定旁白文件(不在分镜解析范围内)
SCRIPT.md是可选的、自由格式的锁定旁白文件,它驱动 TTS,但不会被解析进 Manifest。关键边界:
- 无旁白/TTS 的视频不生成该文件;
- 其格式定义在 script-format.md;
- 分镜中每帧的
voiceover元数据是分镜自身的旁白指引,与SCRIPT.md是两套东西。
仓库中 storyboard-sample 夹具 给出了真实示例:包含 Voice(如Rachel (ElevenLabs))、Voice settings(stability / similarity / style)、Voice direction,以及按行组织的## Line N — 标题,每行带时间区间(如3.0 – 7.0s)、delivery 提示和最终文案。它与STORYBOARD.md同为项目的兄弟文件,位于项目根目录。
六、帧评论通道:.hyperframes/frame-comments.json
分镜评审的结构化反馈通道是.hyperframes/frame-comments.json——Studio 的逐帧评论框提交时写入的文件(聊天反馈遵循同一规则,见 brief-contract.md 第 1 节的评论通道约定)。与SCRIPT.md一样,它是分镜的兄弟文件,不解析进 Manifest:
{ "version": 1, "pass": "sketch", "submitted_at": "2026-07-09T12:04:00Z", "comments": [ { "frame": 3, "src": "compositions/frames/03-mechanism.html", "title": "Mechanism", "text": "Swap the bar chart for a before/after slider." } ] }| 字段 | 含义 |
|---|---|
pass | 这批评论所属的评审轮次:storyboard(文本层)/sketch(静态帧)/final(成片) |
comments[].frame | 帧在 Manifest 中的 1 基index——这是评论的主键 |
comments[].src、title | 提交时从帧上拷贝而来——若提交后帧被重排,不匹配就会暴露出来 |
comments[].text | 反馈原文,逐字保留 |
生命周期契约:工作流在检查点(checkpoint)发现该文件时,将其视为修订反馈——只修订被点名的帧、删除该文件、重新呈现。写作者只在提交时创建它,它绝不跨轮次残留。
七、完整示例与仓库真实夹具
以下是 storyboard-format.md 提供的完整示例:
--- format: 1920x1080 message: "Ship a launch video in an afternoon" arc: Hook → Problem → Solution → Proof → CTA audience: indie devs on X --- ## Frame 1 — Hook - scene: Big type punches in on the beat - duration: 3s - poster: 2s - transition_in: cut - status: animated - voiceover: "Ship a launch video in an afternoon." - src: compositions/frames/01-hook.html Open cold on the promise. This is the thesis — everything after pays it off. ## Frame 2 — The problem - scene: A 20-minute timer spins on a stack of rejected takes - duration: 4s - transition_in: crossfade - status: built - voiceover: "The old way? Prompt, wait twenty minutes, get something that misses." - src: compositions/frames/02-problem.html The old way: prompt, wait, get something that misses. Establish the pain we remove.仓库中还有一份真实运行的分镜文件:storyboard-sample/STORYBOARD.md。这份 5 帧夹具完整演练了分镜契约的端到端行为(见其 README):
- 前 4 帧都有对应的 HTML 子合成(01-hook.html 等),状态为
built/animated; - 第 5 帧
05-cta.html故意缺失且状态为outline,用于让网格渲染出一个轮廓占位符; - Frontmatter 中额外携带了
voice: Rachel — 5 lines from SCRIPT.md这样的未知键——它不会报错,而是被保留在globals.extra中,直观展示了自定义字段的携带方式。
你可以用下面的命令预览分镜视图或检查解析结果:
# 预览 Storyboard 视图 npx hyperframes preview packages/studio/fixtures/storyboard-sample # 查看 Studio 实际消费的解析后 Manifest curl localhost:<port>/api/projects/<id>/storyboard | jq【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考