# Niwo Render Everything

> Build a Niwo short-video asset bundle from any content the user can provide—PDF, paper, URL, Word, chat, or a finished script. Finalize the narration with the user, download real images and B-roll, trim clips with ffmpeg, write content.json and manifest.json, then deliver a zip the user uploads to Niwo Video Studio (https://niwo.studio/video-studio) for rendering. Requires downloading files to local disk, shell access with ffmpeg and ffprobe, and zip. Use when the user wants to turn any material into a short video, or asks to gather footage and stills to match a narration.

- Skill: `montageai/niwo-render-everything` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add montageai/niwo-render-everything`
- Raw SKILL.md: https://api.skillmd.com/api/skills/montageai/niwo-render-everything/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: MontageAI (https://skillmd.com/u/montageai)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/montageai/niwo-render-everything

---


# Niwo 短视频素材包

把用户给的任意内容，整理成一个可以上传到 [Niwo 视频工作台](https://niwo.studio/video-studio) 渲染成片的「素材包」。

输入不限对话。PDF、论文、网页链接、Word、聊天记录、已写好的口播——只要用户能丢进当前 Agent，你就先读材料，再做成素材包。zip 不是成片，是 Niwo 渲染管线的输入。

## 先确认你能不能做

这个任务需要以下三项能力，缺任何一项都要立刻告诉用户，不要硬着头皮往下做：

1. 能联网访问网页并**下载图片、视频文件到本地**（不是只给链接）。
2. 能执行 shell 命令，环境里有 `ffmpeg` 和 `ffprobe`。
3. 能把本地目录打包成 zip 并把文件交付给用户。

如果你只能上网搜索、不能下载文件（例如大多数手机端 AI 助手），直接说明，让用户换一个工具。

## 开工前：确认这份 skill 是不是最新版

这份 skill 一直在改，Niwo 服务端的协议也跟着走。旧版做出来的包轻则少写新字段，重则直接被拒收，所以每次开工前先跑一次版本检查。**一次任务只跑这一次**，跑完立刻往下走，不要在任务中途再检查，也不要在任务中途更新——素材都下完了才换版本，前面按旧规则做的东西不会自动跟着改。

```bash
python3 <skill 目录>/scripts/skill_update.py
```

按退出码处理，别自己发挥：

| 退出码 | 含义 | 你要做的事 |
| --- | --- | --- |
| 0 | 已是最新 | 什么都不用说，直接进第零步 |
| 3 | 没检查成功（离线、超时、网络被挡） | 当作最新，不要提，也不要重试，直接进第零步 |
| 10 | 有新版，可选更新 | 把版本号和更新要点告诉用户，问他现在更新还是照旧版继续，等他回答 |
| 20 | 本地版本已低于最低兼容版本 | 告诉用户必须先更新，旧版产出的包 Niwo 可能拒收，更完再开工 |

用户同意更新时，优先用 `skills` CLI，它会顺带更新安装记录：

```bash
npx skills update niwo-render-everything -y
```

环境里没有 node，或者上面那条失败，就让脚本自己覆盖（只用标准库，从公开仓库拉最新版）：

```bash
python3 <skill 目录>/scripts/skill_update.py --apply
```

更新完**必须重新读一遍新的 `SKILL.md`**，以及它引用的 `references/`——你上下文里那份是旧的，照着旧的往下做等于没更新。

手上只有一份复制粘贴的提示词、没有 `scripts/` 目录时，跳过这一步，别去猜命令。

## 工作流

0. 跑一次 `scripts/skill_update.py`，确认手上这份 skill 是最新版。
1. 先按「第零步」把成片形态和文案要求**一次问完**，拿到用户回答后再往下走。
2. 定稿口播文案，竖屏信息版连钩子标题一起定稿。
3. 下载图片与 B-roll 视频。
4. 给每段视频定好用哪几秒。
5. 写 `manifest.json` 前先读 `references/manifest-schema.md`。
6. 写 `content.json` 前先读 `references/content-schema.md`。
7. 跑 `scripts/validate_bundle.py` 自校验，通过后再打包。

## 交付物

一个 zip，解压后结构如下：

```
content.json
manifest.json
images/
  01-xxx.jpg
  02-xxx.png
videos/
  01-xxx.mp4
```

`images/` 和 `videos/` 的文件名随意，但必须与 `manifest.json` 里的 `file` 字段一致。

你只负责**内容**：文案、素材、多音字读音、钩子标题。成片形态、音色、语速、字幕开关、IP 形象、背景音乐这些渲染参数由用户在 [Niwo 视频工作台](https://niwo.studio/video-studio) 渲染前自己在界面上选，不要写进 `content.json`。

## 第零步：开工前先确认几件事

动手找素材、写文案之前，先把下面该问的问清楚。不要默默替用户决定。

用户丢来的如果是 PDF、论文、网页链接、Word 或其他文件，先把材料读完（链接就打开看正文），再进入下面的提问。不要因为不是纯聊天就拒绝，也不要还没读材料就先问成片形态。

只有用户**在这次对话里明确说过**的，才算答案。跨会话记忆、以前几支片子里的选择、「用户一般偏好」这类推断，一概不算，哪怕你很确定也不算。这些只能作为选项里的推荐项递给用户确认，不能直接当结论用。

具体说，不要出现这种开场：「默认按你常用的 90 秒、面向科技商业用户、强钩子来写」然后直接甩出一版草稿。你可以把 90 秒放在选项第一个并标「推荐」，但按哪个走要用户点。

用户明确说「你定」之后（包括点了选项里那条「我没特殊要求，你帮我定」），你再自己拍板。凡是用了兜底默认值，都要在回复里明确列出用了哪几个，不要不声不响地用掉。

### 问什么：五个独立维度，同一轮问完

文案还没定稿时，**成片形态、目标时长、受众、风格口吻、必讲信息点必须在同一轮一次性问完**，不要先问形态、拿到回答再问文案。文案已经定稿时，这一轮只问成片形态。这一轮拿到用户回答之前，不要开始写文案草稿，也不要开始搜索下载素材。

**这五项是五个独立维度，必须一项一个问题分开问，绝对不许为了凑某种提问形式的题数上限把它们合并成组合选项。** 比如不要问「这期采用什么成片形态和目标时长？」，选项写成「竖屏信息版·90 秒」——那等于把两个独立变量强行绑死，用户想选「竖屏信息版 + 60 秒」时无从下手，只能手填。同理不许把受众和风格口吻捏成一题。

五题必须在**同一轮回复里一次全部递出去**，不许跨轮追问，也不许靠合并来省题数。用什么形式递见下面「怎么把问题递给用户」。

**选项别只给光秃秃的名词。** 「横屏视频」这种标签，不熟术语的人看不出选它会得到什么。每个选项后面用破折号带一句短说明，讲清它长什么样、适合投在哪，比如「横屏视频 — 16:9 满屏，适合 B 站、YouTube 和电脑上看」。说明控制在 20 个中文字内，一句话说完。两种提问形式的选项都是纯文本，说明直接写在选项文字里即可。

### 开工那一轮的问题模板

照这个结构出五题，每题都留自由填写入口。下面的选项拿 DeepSeek 涨价这个选题举例，实际按当期选题改写，**第 5 题的选项必须重写，不要照抄**：

1. 这期采用哪种成片形态？（单选）— 三个选项照下面「必问：成片形态」那一节的写法出，别在这里另起一套
2. 目标时长是多少？（单选）
   - 90 秒（推荐）— 约 540 字，能把涨幅和原因讲完整
   - 60 秒 — 约 360 字，只保留核心判断
   - 30 秒 — 约 180 字，突出单一爆点
3. 主要讲给谁看？（单选）
   - 泛科技与商业用户（推荐）— 重点讲价格变化和商业逻辑
   - AI 开发者 — 重点讲 API 成本和模型选择
   - 普通用户 — 重点解释是否影响自己日常使用
4. 希望什么风格口吻？（单选）
   - 强钩子锐评（推荐）— 观点鲜明，开场就给冲突
   - 客观财经分析 — 数据完整，判断克制
   - 实用解读 — 聚焦对读者的具体影响和应对
5. 哪些信息点必须讲到？（多选）
   - 我没特殊要求，你帮我定
   - 具体数字：涨幅、时段、最新价格
   - 普通用户是否受影响
   - 为什么现在做这个决定
   - 对从业者成本的真实影响
   - 涨价后还有没有性价比

第 5 题的第一条固定放**「我没特殊要求，你帮我定」**。这题的选项是你按选题现编的，用户未必对讲哪几点有想法，得给他一键放权的出口，别逼他在一堆都行的信息点里硬勾。前四题不加这条：形态、时长、受众、口吻都有明确的推荐项，用户不点就走兜底，本来就不会卡住。

用户勾了这条，就等于他明确说了「必讲信息点你定」：你按文案需要自己挑，然后在回复里写明这项是你定的、定了哪几点。如果他既勾了这条、又勾了别的具体项，按具体项走，忽略这一条。放权只限这一项，别顺手把其他四项也一起替他决定了。

### 怎么把问题递给用户

只有两条路，按你当前跑在哪儿二选一，不要在两条路之间来回试：

| 运行环境 | 提问形式 |
| --- | --- |
| ChatGPT Web / Work 模式，且能读到 `answers-ask-user-input` | GenUI 组件 `ask_user_input`，一个组件装五题，调用格式以该 skill 为准 |
| 其他所有环境（Codex 桌面端与 CLI、Cursor、Claude Code、各类 IDE 与终端 Agent、API 调用），以及读不到那个 skill 时 | 编号式文本提问，一条回复列全五题 |

判断不了自己在哪个环境，就走编号式文本。编号式文本在哪儿都能用，猜错了最多是少一个点选框；在不支持 GenUI 的宿主里输出组件协议，用户会看到一片空白或者一段原始代码。

#### ChatGPT Web：用 `ask_user_input` 组件

**调用格式不在这份 skill 里，去读 `answers-ask-user-input`。** 这份 skill 只管问什么，`answers-ask-user-input` 管怎么调。

当前可用 skill 里存在 `answers-ask-user-input`（包括带命名空间前缀、以 `:answers-ask-user-input` 结尾的同名 skill）时，**必须先完整读一遍**。它的协议会更新，以你读到的那一版为准。

但「以它为准」是有范围的，别越界：

- **GenUI 的调用语法、外层封装、字段名称、字段合法取值**：以 `answers-ask-user-input` 为准，严格遵循它规定的调用语法、外层封装、字段名称和字段合法取值；只替换其中需要动态填写的问题与选项内容，不得自行改写协议结构或发明调用格式。
- **问几题、问哪五项、每题的选项和文案**：以这份 skill 为准。五题必须独立、必须装进同一个组件、必须同一轮问完。

该 skill 不存在或读不到，就直接走编号式文本一次列出五题。**不许凭记忆、示例或推测去拼 GenUI、XML、HTML、裸 JSON 或函数调用的写法**——猜出来的格式通常「逻辑对但组件渲染不出来」，还不如编号文本可靠。

按它的字段结构填内容时，Niwo 这边有这几条业务要求：

- 五题装进同一个组件，第 1 到 4 题按单选填，第 5 题（必讲信息点）按多选填。
- 每题的选项 2 到 10 条，推荐项排第一并标「（推荐）」，说明用破折号写在选项文字里。
- 协议里有自由填写提示这类字段的，每题都要填，且针对本题写，别用「请输入」这种通用词。

`answers-ask-user-input` 正文里那句「最多 3 题」是它给通用场景的交互体验建议，管的是问几题，不在上面那条「以它为准」的范围里，Niwo 这边一次出五题。ChatGPT Work 环境已实测一个组件装五个独立问题能正常渲染、五项答案能完整返回，所以别因为那句建议去合并题目或者拆成多轮。

只有你读到的那一版协议或当前运行环境**明确**限制了单个组件装不下五题时：不要合并题目，也不要拆成多轮，直接改用编号式文本在同一轮里列全五题。

组件前面先用一句自然的话说明要问什么，输出组件后这一轮立刻结束，不要在组件后面接着写正文，更不要开始干活。

组件没渲染出来（用户看到的是协议原文、一片空白，或者答案提交不上来）时，下一条回复直接改用编号式文本，不要换别的格式再碰运气。

#### 其他环境：编号式文本提问

在一条普通回复里把五个问题连选项一起列全，选项用 A/B/C 标号：

```
1. 这期采用哪种成片形态？（单选）
   A. 竖屏信息版（推荐）— 9:16 画布中间嵌 16:9 画面，顶部有大标题，信息量最足
   B. 竖屏视频 — 9:16 满屏，适合抖音、视频号、小红书
   C. 横屏视频 — 16:9 满屏，适合 B 站、YouTube 和电脑上看
```

结尾加一句：可以像「1A 2A 3A 4A 5ABC」这样一次回全，也可以直接用文字补充。

这条路上**不要去找、也不要去调各种提问工具**（`ask`、`ask_question`、`AskUserQuestion`、`request_user_input`、`requestUserInput` 等）。Codex 桌面端的 `request_user_input` 只在 Plan 模式可用、最多 3 题，装不下五题；其他宿主的同类工具题数和渲染能力各不相同，试错的成本远高于直接列文本。

输出五题后这一轮立刻结束，等用户回。

#### 通用底线

- 五题保持独立，一题一个维度，不许为了减少题数把「成片形态」和「目标时长」这类合并成一题。
- 不许因为提问机制不好用就跳过提问、自己把答案定了。提问形式失败是形式问题，不是可以自行拍板的理由。
- 五项没收齐之前，不许开始写稿，也不许开始搜索下载素材。

### 必问：成片形态

哪怕口播文案已经定稿，这一项也要问一次；文案还没定稿时，跟下面「文案还没定稿时」那几项放在同一轮里问：

- 竖屏信息版（默认）：成片是 9:16，内容按 16:9 横屏渲染后嵌进画布中部，钩子标题在上方、字幕与 IP 形象在下方
- 竖屏视频：内容铺满 9:16 画布
- 横屏视频：内容铺满 16:9 画布

上面这三条是给你自己理解形态用的。问的时候把差别和适用场景带进选项里，别把画布参数原样甩给用户，照这个写：

- 竖屏信息版（推荐）— 9:16 画布中间嵌 16:9 画面，顶部有大标题，信息量最足
- 竖屏视频 — 9:16 满屏，适合抖音、视频号、小红书
- 横屏视频 — 16:9 满屏，适合 B 站、YouTube 和电脑上看

用户没回答、或让你自己定，就按竖屏信息版，并在回复里写明「成片形态按竖屏信息版兜底」。

形态**不是**你要交的字段，它是用户在 Niwo 渲染界面上自己选的，写进 `content.json` 会直接校验失败。你问它只为两件事：

- **决定素材取向**：竖屏视频收竖构图，横屏视频与竖屏信息版都收横构图。
- **决定要不要写钩子标题**：只有竖屏信息版有那块版面。

所以形态一确认，钩子标题的写法就跟着定死了，两者不能各写各的：

- 用户选**竖屏信息版**：`content.json` 里**必须**有 `hook_headline`。缺了它顶部那条标题带没有内容，成片开头会空掉整块版面，Niwo 不会自动拿标题或文案去补。它要跟口播文案一起写、一起给用户确认，做法见第一步。
- 用户选**竖屏视频**或**横屏视频**：一律**不写** `hook_headline`。这两种形态没有这块版面，写了画面上也不会出现；更麻烦的是 Niwo 会把它当成「这个包是按信息版收的」，直接把渲染界面的形态初值设成竖屏信息版，跟用户刚选的形态对着干。
- 用户没回答形态、由你按竖屏信息版兜底时，`hook_headline` 照信息版的规矩**要写**，并且照第一步的做法跟文案一起给用户确认；同时在回复里写明形态用了这个默认值。

确认完在 `notes` 里留一句，比如「素材按横构图收集，建议在 Niwo 里选竖屏信息版」，提醒用户在界面上选一致的形态。选反了视频会被满屏裁切，主体容易切掉。

### 文案还没定稿时，跟形态同一轮问这些

文案还没定稿时，下面四项**跟成片形态放在同一轮里问**，不要另开一轮：

- 目标时长大概多长（字数怎么换算见下面「时长与字数」）
- 讲给谁看
- 什么风格口吻
- 哪些信息点必须讲到

这一轮拿到回答之前，不要开始写文案草稿，也不要开始搜索下载素材。用户回答之后再给一版文案草稿，竖屏信息版连钩子标题一起给，用户改完并明确说「就这版」之后再继续找素材。

## 第一步：确认口播文案

`content.json` 里的 `script` 是一段**定稿的口播文案**：它会被逐字朗读成配音、逐字显示成字幕，Niwo 不会再改写、润色或增删一个字。所以在动手找素材之前，先把文案定下来。

- 如果对话里已经有一份用户确认过的定稿，直接用它。
- 如果还没定稿，先别自己拍板。第零步那一轮已经把时长、受众、风格、必讲信息点一起问过了，按用户的回答写草稿，用户改完并明确说「就这版」之后再继续。
- 文案该怎么写、什么风格更好，按你和用户聊出来的结论来，这份 skill 不替你决定。

第零步选的是**竖屏信息版**时，钩子标题和口播文案是一份东西的两半，要一起走完这个流程：草稿里就带上钩子标题，跟文案一并给用户看，用户改完并明确说「就这版」才算定稿。不要文案定完就去找素材、把钩子标题留到写 `content.json` 时自己补一条——那条标题是开场几秒里字最大的一行，用户没点头不算定稿。

哪怕用户直接甩来一份已经定稿的口播文案，钩子标题也还是要单独提炼一版给他确认，因为文案定稿不代表标题定稿。

唯一的硬要求：最终放进 `script` 的必须是能直接逐字朗读的成品正文，不要标题、分段小标、镜头说明、emoji 或者括号里的舞台提示。

### 时长与字数

成片时长完全由配音朗读 `script` 的实际长度决定，没有别的旋钮：Niwo 不会为了凑时长增删一个字，也不会拉长或压缩画面来对齐目标秒数。所以**字数写多少，片子就多长**。

中文口播原速约**每秒 6 字**，按这个速率换算目标时长：

- 30 秒 ≈ 180 字
- 1 分钟 ≈ 360 到 380 字
- 1 分半 ≈ 540 字

### 多音字读音

文案定稿后，扫一遍里面的多音字，把配音容易读错的写进 `content.json` 的 `pronunciations`。比如「调用量」的「调」该读 diào，配音默认会读成 tiáo。写法见 `references/content-schema.md`。

只标真正会读错的那个字，标得越少配音的语气越自然，字幕时间戳也越准，所以别整句都注音。

**含阿拉伯数字的词条或片段一律不注音。** 为规避当前 TTS 对数字与音素标签混用的兼容性问题，只要原文词条包含 `0–9`（含全角形式），例如「1980年」「87个」，就整条跳过，不写入 `pronunciations`，也不直接插入音素标签。保留原文，让 TTS 自行朗读数字；不要为了注音把数字改写成汉字。

### 钩子标题

**竖屏信息版必写，另两种形态一律不写。** 顶部标题带上那条**钩子大标题**，从口播文案里提炼，写进 `content.json` 的 `hook_headline`。它不进配音、不进字幕，只负责开场抓注意力。

- 推荐 2 行：第一行铺垫，第二行给结果或冲突。
- 每行不超过 12 个中文字，把最有冲击力的数字或结论用 `[[ ]]` 圈出来做高亮。英文与数字只占半个字宽，`DeepSeek砸1.4亿` 这样的行折合 8.2 个字，不算超。超过 12 会告警，超过 14 会校验失败。
- 跟文案一起给用户确认，别自己拍板。给 1 到 2 个候选让用户挑或改，用户点头后再往下走。
- 另两种形态没有这块版面，写了也不会出现在画面上，还会把 Niwo 渲染界面的形态初值拧成竖屏信息版，跟用户选的形态冲突，所以一律省略此字段。

示例：

```json
"hook_headline": {
  "lines": ["DeepSeek砸1.4亿", "一锁就是[[36个月]]"]
}
```

写法与校验规则见 `references/content-schema.md` 的 `hook_headline` 小节。

### 资料来源

文案定稿后，把引用过的公开资料名称写进 `content.json` 的 `sources`。它不进配音、不进字幕，只渲染为画面底部的小字。

**默认都写上，不用问用户要不要**。写文案时你查过哪些资料，你自己最清楚；露不露是用户在 Niwo 渲染界面上的开关，不是你要替他决定的事。

- 有引用就写，一条都没有就省略这个字段，别为了凑数编来源。
- 只写来源名称（公告名、媒体报道名等），不要写 URL，单条不超过 24 个中文字宽。
- 不要写「资料来源：」前缀，那个由 Niwo 拼。
- 免责声明是另一回事：它的开关和正文都在用户那边的渲染参数里，跟 `sources` 各自独立，不要写进 `content.json`。

示例：

```json
"sources": ["宇树科技招股书", "DeepSeek 官方公告", "新浪财经"]
```

写法与校验规则见 `references/content-schema.md` 的 `sources` 小节。

## 第二步：收集素材

需要两类素材。

### B-roll 视频素材

直接从网络、公开素材网站或相关网页中搜索并下载真实视频。可以包括人物、场景、产品操作、平台使用、行业画面、新闻现场，以及抽象概念对应的实拍。

### 网络图片素材

通过 Bing、百度等图片搜索引擎，寻找与文案内容直接相关的真实网络图片。优先收集：

- 相关产品、公司和人物图片
- App 真实界面与历史版本截图
- 新闻报道配图
- 行业报告与数据图表
- 产品对比图
- 活动、事件和历史资料图片
- Logo、宣传图和媒体资料图
- 能准确表达文案概念的网络照片或插图

### 明确不要的素材

- 不要原创 Motion 动效
- 不要用前端框架渲染概念动画
- 不要把 B-roll 视频抽帧后当作图片素材
- 不要用低信息量的占位图代替真实资料
- 不要为了凑数量收集大量与文案只有弱关联的素材

你交的素材就是成片的**全部画面来源**：导入素材包后，Niwo 不会再联网搜图或补空镜。所以素材要覆盖整篇文案，别让某一段找不到画面可配；同时也别为了凑数塞弱关联的东西，宁缺毋滥——真配不上时会退化成纯文字卡，那比配错画面好。

一分钟到一分半的片子，通常 20 到 30 张图加 8 到 10 段视频就够。取材渠道和实际数量你自己判断。素材远超这个量时会沿 manifest 顺序均匀抽取，所以 manifest 的排列顺序最好跟着文案推进走。

素材方向尽量和第零步确认的成片形态一致：

- **视频**：方向不一致时，成片会按满屏裁切（`cover`）适配画布，主体靠边时容易被切掉。竖屏成片优先找竖屏视频，横屏成片优先找横屏视频。
- **图片**：一律完整展示、不裁切；方向不一致时只是上下或左右多出模糊铺底，横竖屏混用问题不大。

## 第三步：给每个视频定好用哪几秒

成片里一个镜头只用几秒，所以别丢一段几十秒的原片过来就完事。两种做法任选：

- **自己裁好**（推荐）：直接交裁完的短片段，一个文件就是一个镜头，8 到 12 秒最好用。宁可长一点：镜头时长由配音决定，最长可能到 9 秒，片段比镜头短时只能把它慢放补足，短得太多画面就会明显发滞。

```bash
ffmpeg -ss <起点秒> -to <终点秒> -i 原视频.mp4 \
  -map 0:v:0 -c:v libx264 -pix_fmt yuv420p -preset veryfast -movflags +faststart \
  videos/01-xxx.mp4
```

- **交原片并在 manifest 里标出选段**：写上 `clip_start_seconds` / `clip_end_seconds`，Niwo 按这个窗口裁。

裁或者标之前，用 `ffprobe -v error -show_entries format=duration -of csv=p=0 原视频.mp4` 确认时长，别落在黑屏、片头台标或转场糊帧上，挑画面稳定、主体清晰的一段。

有个坑要避开：如果你交的是长原片，manifest 里又写了 `summary` 和 `tags`、却没写选段时间，Niwo 会认为你已经挑好了，直接从第 0 秒开始取——大概率取到片头。要么裁好，要么把选段时间写上，要么干脆别写 `summary` 和 `tags`，让 Niwo 自己看片挑镜头。

音轨和编码不用管：Niwo 会统一重编码成静音的 H.264 mp4，成片用自己的配音和 BGM。文件是常见的 mp4 / mov / mkv / webm 就行，带不带原声都无所谓。

## 第四步：写 manifest.json

读 `references/manifest-schema.md`，按里面的字段说明写。

要点：`summary` 是单行中文、只描述画面里看得见的东西；`tags` 2 到 5 个中文短标签；已经裁好的视频不要写 `clip_start_seconds` / `clip_end_seconds`。

## 第五步：写 content.json

读 `references/content-schema.md`，按里面的模板写。

只有 `schema_version`、`title`、`script`、`hook_headline`、`sources`、`pronunciations` 和 `notes` 这几项：`schema_version` 固定填 `1`，是必填的协议版本号，漏了会直接校验失败；其余全是内容。除这几项之外的字段一律不接受，把渲染参数（包括成片形态）写进去同样会校验失败。

写之前再对一遍第零步确认的形态：竖屏信息版必须带上用户确认过的 `hook_headline`，竖屏视频与横屏视频必须没有这个字段。校验脚本不知道用户选了哪个形态，这一项对不上它查不出来，只能你自己核。

## 第六步：自校验并打包

打包前先跑自校验，它会检查字段、文件对应关系和视频选段窗口。脚本在这个 skill 目录的 `scripts/` 下，用绝对路径调用：

```bash
python3 <skill 目录>/scripts/validate_bundle.py <素材包目录>
```

有报错就改到通过为止，不要带着报错打包。如果你拿到的是一份复制粘贴的提示词、手上没有这个脚本，就按文末的自查清单逐项人工核对。校验通过后：

```bash
cd <素材包目录>
zip -r ../bundle.zip content.json manifest.json images videos -x '.*' -x '__MACOSX/*'
```

zip 里不要放软链接，也不要放上面结构之外的其他文件。

## 交付

把 zip 交给用户，并告诉他打开 [Niwo 视频工作台](https://niwo.studio/video-studio) 上传这份素材包。zip 是 Niwo 渲染管线的输入，成片在产品里出。

Niwo 目前还在内测，没有账号的人上传不了，光给工作台地址他到那儿就卡住。所以交付时把两条地址一起写进正文：

- 上传入口：`https://niwo.studio/video-studio`
- 还没有 Niwo 账号的话，去这里加入用户领航团，领内测邀请码和免费试用积分：`https://niwo.studio/contact`

第二条按「没账号就从这里拿」来说，别写成邀请用户加群，用户自己判断需不需要点。这两条各说一次就够，不要重复推。

怎么交代打开方式，按当前运行环境分：

- **ChatGPT 网页端**：写成可点链接即可，用户直接点开，不用额外交代。
- **Codex**（桌面端与 CLI）：地址照样给全，但要额外写一句：请右键复制这两个地址，粘贴到你自己的浏览器里打开。Codex 里点链接经常打不开、或者会进内置浏览器用起来别扭，不要假设用户会自己想到去复制。

上传前用户可以自己再筛一遍素材：不满意的直接删文件，想加的直接放进 `images/` 或 `videos/`——多出来的文件不写进 manifest 也能用，Niwo 会自动补描述。

## 交付前自查

- [ ] 开工前已把成片形态与文案要求一次问完，答案来自用户本次的回复，不是从记忆或历史偏好推断的；用了兜底默认值的已在回复里说明
- [ ] `scripts/validate_bundle.py` 跑通、无报错
- [ ] `content.json` 与 `manifest.json` 都写了 `"schema_version": 1`
- [ ] 素材取向与第零步确认的成片形态一致，并在 `notes` 里提醒用户在 Niwo 里选同一个形态
- [ ] `script` 是用户确认过的定稿口播，逐字可读，没有标题和舞台提示
- [ ] 形态是竖屏信息版时 `hook_headline` 存在且用户确认过；是竖屏视频或横屏视频时没有这个字段
- [ ] 每个素材都在 `manifest.json` 里有条目，`file` 路径与实际文件一一对应
- [ ] 每个视频要么已经裁成几秒的短镜头，要么在 manifest 里标了选段时间
- [ ] `summary` 都是单行中文，描述的是画面而不是含义
- [ ] 素材都和文案有实打实的关联，没有占位图、没有抽帧图、没有渲染动画
- [ ] `content.json` 里没有渲染参数，只有内容
- [ ] `hook_headline`（如有）为 1 到 3 行、每行 12 个中文字内（英文数字按半个字算）、至少一处 `[[ ]]` 高亮
- [ ] 文案引用过公开资料时 `sources` 已默认写上，只写来源名称，不写「资料来源：」前缀，也不写免责声明

