动态排版导演
您与用户一起导演整个视频的排版。您起草一份排版剧本:为每行文字选择一种技术,并根据其含义挑选。用户会看到一个页面,预览并更改它,然后批准。之后,您便在 Remotion 中精确地构建他们批准的内容。
创意自由优先。 以下所有内容都是默认设置,而非规则。当某个时刻需要其他做法时,就去做,并在该行的一句话理由中说明原因。用户通过页面拥有最终决定权。
在步骤中,<skill> 指此技能所在的文件夹(当技能加载时,Claude Code 会将其显示为基础目录)。kinetic-type 技能位于其旁边,路径为 <skill>/../kinetic-type。
1. 首先加载 kinetic-type
加载 kinetic-type 技能(使用技能工具)并打开其 references/menu.md。您使用的每个技术 ID 都来自该菜单,其构建部分说明了如何在第 6 步中构建。不要保留您自己的列表。
2. 收集信息
- 脚本。 如果用户未提供,请询问。将其拆分为屏幕上显示的每一行,每行一个短语或一个想法。尊重用户自己的换行。
- 宽高比: 默认为
16:9,除非用户另有说明(手机视频用9:16,正方形用1:1)。 - 模式: 默认为教学,除非用户另有说明。“发挥创意”、“尽情发挥”或“给我惊喜”意味着自由发挥。
- 时间安排。 根据大声朗读所需的时间,估计每行开始 (
t) 和持续 (dur) 的秒数,并在需要停顿的地方留出节拍。这只是一个猜测:没有音频,画外音是稍后录制的。
不要因为可以用默认值回答的问题而耽误进程。说明您使用了哪些默认值。
3. 起草排版剧本
- 三个基础选项: 选择三种平静的技术(在菜单中标记为 calm),这些技术适合主题和语气,每个选项附带一行理由。您的首选是
house。(页面只接受平静的基础选项;更大胆的外观仍然可以是任何行的style。) - 每一行:
style是"house"或一个强调技术的 ID,key是最重要的那个词(或""),suggest列出您为该行推荐的选项,每个选项附带一行理由。普通行可以有一个空的suggest。 - 教学模式(默认):基础风格承载普通行,而少数几个强调技术标记出重要的时刻:关键术语、答案、警告。标记为 teach 的技术很适合做强调技术。少即是多。
- 自由发挥: 菜单上的任何技术,仍然根据含义选择。自由不意味着使用很多。
- 退场(标记为 exit:shatter, disintegrate, smoke dissolve, zoom through a letter)以文字消失结束。将它们放在文字应该消失的地方,例如场景的结尾或最后一行,并在理由中说明。
- 打破默认规则是可以的。将原因写在理由中,例如“课程中的自由发挥选择:答案值得一个爆点。”
4. 制作页面并打开它
从用户视频项目的根文件夹运行以下命令。
- 将数据写入项目中的
type-script/<slug>.json。<slug>是一个短的短横线命名(kebab-case)名称,例如pythagoras。字段及完整示例见references/type-script-format.md。 - 制作页面:
如果失败,它会列出所有问题并且不写入任何文件。修复数据后重新运行。node "<skill>/scripts/make-page.mjs" type-script/<slug>.json type-script/<slug>.html - 通过 HTTP 提供文件夹服务,作为后台命令运行(浏览器窗格将
file://页面显示为静态图片):为此项目选择一个端口(默认为 3018),并且始终为同一个项目使用相同的端口。页面会按地址保存用户的选择,因此不同的端口会显示一个新的页面。如果端口显示被占用,则服务器可能仍在运行,只需打开页面即可。node "<skill>/scripts/serve.mjs" type-script <port> - 在内置浏览器中打开
http://127.0.0.1:<port>/<slug>.html:如果尚未打开窗格,则使用preview_start指定url,或使用navigate。
如果没有内置浏览器,请将 type-script/<slug>.html 的路径提供给用户,让他们在自己的浏览器中打开,并在第 5 步中使用“复制选择”作为后备方案。
5. 移交控制权,然后读取选择
用几句话告诉用户您起草的内容(基础选择和强调技术)以及如何使用页面:
- 点击一个单词使其成为关键词
- “Swap” 更改一行的风格
- “+ note for Claude” 在某行上留下备注
- “Looks good: send to Claude” 确认
请他们完成后说 “done”。
当他们完成后,使用浏览器的 javascript_tool 在打开的页面上读取结果:
JSON.stringify(window.TYPE_SCRIPT_RESULT)
它包含 { title, mode, house, lines: [{ text, key, style, note }], approved, draft }。style: "house" 表示所选的基础选项。如果无法读取,请要求用户按 Copy choices 并粘贴它复制的内容。JSON 对象在最后。
- 在构建前检查
approved === true。 如果为 false,则表示他们没有按“看起来不错”,或者之后更改了某些内容。询问是继续还是等待。 - 备注 是用户对该行的请求。在构建中遵循它们。如果某个备注更改了计划,请说明您的理解。
- 将您读取的内容保存为
type-script/<slug>.choices.json,以便选择在会话后仍然保留。
当需要重新生成页面时(新行、更改的文本或时间,或者用户要求的全新自由发挥草稿):
- 首先读取
TYPE_SCRIPT_RESULT。基于更改后的数据制作的页面会从头开始。 - 将他们之前的选择纳入新数据:
- 他们选择的基础选项放入
house,如果houseOptions中没有则也放入(替换其他两个之一)。 - 他们的风格和关键词放到匹配的行上(
style,key)。如果他们选择了您未推荐的风格,也将其添加到该行的suggest中,如果他们有给出理由,则加上理由。 - 数据没有备注字段,因此在新草稿中,针对每条备注采取行动,并在该行的理由中说明(例如“您要求更具冲击力:用 stomp 代替 fade”)。
- 他们选择的基础选项放入
- 重新生成页面,然后在同一端口上重新加载。
6. 在 Remotion 中构建
遵循 kinetic-type 的“在 Remotion 中构建”部分:将其 remotion/ 文件夹复制到项目中,作为 src/kinetic-type/,并以项目精确的 Remotion 版本安装它命名的包。使用 npm i -E 以便 npm 保存精确版本(普通 npm i 会保存 ^4.0.536,这可能会后来漂移到更新的、不匹配的版本)。然后为该视频编写一个 composition,放在单独的文件中,例如 src/<Name>.tsx:
- 尺寸: 16:9 为 1920×1080,9:16 为 1080×1920,1:1 为 1080×1080。使用 30 fps。长度是最后一行的结束时间(
t + dur)。 - 背景: 组件是透明的,因此在它们后面放置页面的纸张颜色(
src/kinetic-type/kit中的C.paper)。黑暗技术会自带深色背景。 - 每一行 在估计的时间点放入一个
<Sequence>,使用KT_COMPONENTS并传入批准的风格和关键词:
import { AbsoluteFill, Sequence } from "remotion";
import { KT_COMPONENTS } from "./kinetic-type";
import { C } from "./kinetic-type/kit";
const FPS = 30;
const HOUSE = "word-by-word-reveal"; // the approved house
const LINES = [
// t and dur from type-script/<slug>.json; key and style from the approved choices
{ t: 0, dur: 4.5, text: "Every right-angled triangle hides a secret.", key: "hides", style: "house" },
{ t: 25, dur: 4.5, text: "But ONLY for right angles.", key: "ONLY", style: "slice" },
];
export const TypeVideo: React.FC = () => (
<AbsoluteFill style={{ background: C.paper }}>
{LINES.map((l, i) => {
const Comp = KT_COMPONENTS[l.style === "house" ? HOUSE : l.style];
return (
<Sequence key={i} from={Math.round(l.t * FPS)} durationInFrames={Math.round(l.dur * FPS)}>
<Comp text={l.text} keyWord={l.key || undefined} />
</Sequence>
);
})}
</AbsoluteFill>
);
- 如果某个风格不在
KT_COMPONENTS中,它是一个example技术。为那一行调整菜单中命名的场景。 - 在
src/Root.tsx中将其注册为一个<Composition>,使用上述的尺寸、fps 和长度。在一个新项目中,它会替换模板的占位符 composition。
7. 预览,仅在用户要求时渲染
- 首先自己检查工作:从几行的中间渲染一张静态图片(
npx remotion still <id> out/check.png --frame=<n>)并查看。 - 然后让用户观看:在后台运行
npx remotion studio --no-open(如果不加--no-open,它也会弹出用户自己的浏览器)。在内置浏览器中打开它打印的地址(通常是http://localhost:3000)。 - 仅在用户要求时渲染:
npx remotion render <id> out/<slug>.mp4。
如果他们在观看后希望更改,小的改动直接进入 composition。对于大的改动,回到第 4 步,并将他们的选择纳入其中。