Motion reel
在此仓库自己的引擎中构建一部新电影。除非用户指名,否则不要切换到 Remotion 或 HyperFrames;仓库的渲染合约在 CLAUDE.md 中,优先于本文件。
一部电影分两个会话运行,以所有者一次确认镜头列表和分镜板为分界:
- 预制作(本文件):简报、故事、素材、配音、节拍网格、镜头列表、分镜板。
- 构建(
/motion-reel build <film>):阅读 build.md 并遵循它;跳过本文件。
此分界将构建阶段保持在新上下文中。预制作阶段在窗口中填满参考资料、拍摄照片和分镜板图像,后续每一轮对话都将为其买单。
1. 确定简报
在用户草稿上运行 node tools/brief.mjs --in=<draft.md>(当项目存在时使用 --film=<film>:它会写入 brief/original.md,不含嵌入的 base64)。它打印标题、配音词字数(是否在预算内)以及草稿中留空的内容。如果没有草稿,则根据请求填写 docs/brief-template.md 的标题字段,并为每个空缺提出默认值:用户只需回答“oke”或给出更正。
在接触代码和引用提示词之前,一次性询问还有哪些内容未定;brief/decisions.md 中已有的答案保持不变。添加工具无法看到的内容:
- 重叠:过去在同一主题或支柱上的电影(
projects.json)。指出是哪部,以及本片新增了什么。重制版保持旧文件夹不变,并询问其decisions.md中的哪些答案仍然有效。 - 产品 + URL(或主题)。对于 OpenView 影片,支柱和公式来自
docs/content-map.md。 - 品牌:OpenView 影片使用
lib/brand.js。其他品牌:颜色、字体、一个强调色、真实徽标。 - 参考:一帧、视频或图像文件夹。或者“无”(如是则说明;无默认外观)。
- 音乐:提供的音轨(测量其长度)或“合成”(默认)。
- 配音:需要
.env中的ELEVENLABS_API_KEY。如果为空,则停止并提示变量名。
当语言、配音、时长、比例、主题(包括 ticker)、数据源(应用、工具包或插图)和能量全部确定后,简报才算完成。在过去电影的第一版之后,每一项都有过改动,而 mi-demo-40 为它的 VO 付了三次费。将答案记录在 <project>/brief/decisions.md 中。
来自其他工具的包(故事板、压缩包、交接包):原封不动地复制到 <project>/references/<tool>-<date>/,该目录不留存提交记录,然后仅针对其简报运行 tools/brief.mjs。仅当某个决策需要时,才打开其中的另一个文件。其镜头列表和脚本是实质内容,如同草稿的顺序。
限制:简报或法律规则禁止出现在屏幕上的词语、数字或事实,放入 <src>/forbid.json(tools/forbid-lib.mjs):tools/vo.mjs 在花费提示词之前拒绝它们,tools/check.mjs 在屏幕上检测到它们时失败。无法通过模式检测的限制(例如永远不会带百分比的名称)放入 brief/decisions.md,并在每次分镜板和审查表时读取。
选择一个电影 slug([a-z0-9-]+)。以下所有内容都以它命名:<film>。
项目布局。 新电影获得其 CONTENT 项目文件夹(CLAUDE.md“新视频项目文件夹”),并在 projects.json 中添加一行 "<film>": "CONTENT/<n>. <标题> (<日期>)";工具随后会在那里找到它(tools/paths.mjs):镜头列表和简报在 <project>/brief/ 中(shotlist.md),代码在 <project>/src/ 中(film.js、timeline.js、vo-lines.json、beats.json、sfx-<film>.mjs),拍摄照片和媒体在 <project>/assets/ 中,分镜板、审查表和渲染输出在 <project>/output/ 中。较旧的电影保留 docs/<film>-shotlist.md、film/<film>/、assets/<film>/ 和 out/。下文中的 <shotlist>、<src>、<assets> 和 <output> 指代适用的路径。
2. 预制作
-
素材。 进入
<assets>/,在开始任何动画之前列出。- OpenView 徽标和符号:仅通过
lib/brand.js绘制;不要将 SVG 复制到电影中。 - OpenView 吉祥物:
lib/mascot/中的代码骨架(API 在lib/mascot/index.js的头部和导出中)。 - OpenView Market Intel:来自最新
origin/main的数据和名称,使用 Market Intel UI 工具包在代码中绘制图片。仅当简报要求真实应用时才捕获运行中的应用;然后遵循CLAUDE.md中的“Market Intel source”;从capture_mi.mjs --review中选择波段,并使用lib/proof.js绘制。 - 另一个带有 URL 的产品:使用 Playwright 捕获真实截图、徽标、颜色、字体。
- OpenView 徽标和符号:仅通过
-
视觉世界。 阅读
REFERENCES/motion/visual-grammar-2026-10.md,然后在<shotlist>顶部、任何镜头之前编写## 世界:一个地方、它的物体、站在其中的人物、光线的作用,以及简报中的每个图形和关系如何变成你可以指点的东西。使用lib/world.js绘制它。设计系统保留在产品自身的屏幕上。 风格指南。 如果存在参考,首先测量它:uv run --python 3.11 --with librosa --with numpy tools/ref_probe.py refs/<film>/ref.mp4 refs/<film>/analysis.json然后编写docs/<film>-style_guide.md:调色板(十六进制)、类型、镜头时长、转场、摄像机运动、纹理、文字如何进入和退出。采用语法,绝不采用内容。统一外观是CLAUDE.md中的“Look”加上docs/motion-vocab.md;其他电影的风格指南记录那些电影,而非统一外观。 -
故事。 阅读 story.md,将主题置于其主题阶梯中,并在
<shotlist>顶部、任何脚本之前编写其主干表格。当每一行都被填写且该文件末尾的脚本测试通过第一行和大纲时,主干完成;草稿的顺序是这里的实质内容,而不是脚本;草稿中的ALUR CERITA和KANDIDAT HOOK(docs/brief-prompt.md)是其初版。展示带有配音引语的主干:这是改变电影成本最低的时刻。对于草稿,在同一条消息中指出草稿涵盖的内容以及脚本删除的内容,并给出两者的字数:pandu-supra-80在其第一部电影后回复为“ga selengkap draft”,而扩展现花了三个会话。 -
配音(如果简报包含 VO):遵循
CLAUDE.md中的“配音”。基于主干以调查者口吻(story.md“观众”)编写脚本,不超过字数预算,边说边计数数字:印尼语的 1.7 相当于六部电影以 1.12(1.65–1.75 词/电影秒)运行,因此完整预算接近简报的秒数。character默认为calm, fair narrator, talking to one person。然后是<src>/vo-lines.json和 story.md 的最后一节,直到tools/script.mjs通过;其credits行就是引语。使用tools/vo.mjs生成,并传递--check。定义和法律术语需要像任何数字一样在references/sources.md中注明来源;R-120 将注册名称保持在屏幕外,而不是来源文件之外。 拍摄照片设定场景长度:<src>/timeline.js是基于lib/vo-clock.js的场景列表(sceneTimeline;模型:iata-55),node tools/prepare.mjs --film=<film>检查拍摄照片并将时钟写入beats.json。 -
节拍网格。 提供的音轨:测量 BPM/节拍/下拍/重拍(librosa)到
<src>/beats.json中。 合成音效:选择 BPM,编写<src>/sfx-<film>.mjs,一个基于lib/synth.mjs的提示列表(模型:iata-55 的src/sfx-iata-55.mjs),使其输出beats.json和<output>/<film>-audio.wav(-14 LUFS)。 -
镜头列表。 基于节拍网格编写
<shotlist>:每个镜头包括帧数、摄像机、屏幕文字、音效、其主干节拍、使用的docs/motion-vocab.md中的效果,以及切到下一个镜头的理由(下一步、相同位置、因果关系、时间跳跃、回调、尺寸变化)。没有理由切换的镜头将作为摄像机运动合并到下一个镜头中。规划进入产品的路径作为一个运动,一个世界对象变成屏幕,在切割两侧的镜头中命名:它在delisting-18-80(45–50 秒)上吸引了所有者唯一一次创造性的构建修改。在这里规划密度,场景依次:每个镜头将承载的运动量,因为最近每部电影的首次构建在密度上得分为 4-5,并在后续轮次中增加密度。列出需要所有者批准的决策。不要在此停止:镜头列表与分镜板一起交给所有者。 -
分镜板。 首先在
<src>/film.js中绘制电影最宽和最紧的镜头(导出board: [{ t, shot, note }]),然后单独查看这对镜头(node tools/board.mjs --film=<film> --only=<wide>,<close>,其-view.jpg):它们展示了世界必须容纳多少内容,以及图形在特写中是否还能存活,而重绘需要两个镜头的代价。然后为每个镜头绘制一帧。 运行node tools/board.mjs --film=<film>。其文本是机械审查:修复每一条warn … mid-move行(将t移动到已确定的帧)和每一条layout发现(文字超出安全区域、在字幕带中、重叠、太小),然后再次运行以确认文字干净。 仅阅读分镜板的-view.jpg概览,或超过 18 个镜头时阅读其打印的pages,每个页面一次,用于外观检查:在一次遍历中修复任何读起来不对的地方,不要有 look-patch-rerender 循环,不要有逐场景的表格(--scenes存在是为了给所有者使用,不是为了这种审查)。 外观测试,在该概览上:静音并仅凭图片跟随故事;陌生人应该看到一个地方、人物和事物,而不是幻灯片。除了字幕,一个镜头最多容纳 6 个词,位于对象上;简报要求完整出现的证明板和行是唯一的例外。如果失败,则重绘镜头,而不是修剪文字。 -
所有者审查(唯一的关卡)。 同时展示镜头列表和分镜板(
<output>/<film>-board.png),附上需要批准的决策,并等待那一次批准。在此之前禁止运动或声音。 -
交接。 当所有者批准审查时,在
<shotlist>顶部编写一个## 构建简报小节:已批准的内容、仍待定的内容以及构建所需的文件(电影模块、拍摄照片、节拍、音效脚本)。然后在一个新上下文中开始构建:- 桌面应用:使用新上下文(非分支)启动新会话,提示
/motion-reel build <film>。 - 终端:告诉所有者运行
/clear,然后/motion-reel build <film>。
预制作在此结束:所有者对镜头列表和分镜板的批准是完成标准,构建属于新会话。
- 桌面应用:使用新上下文(非分支)启动新会话,提示
3. 硬性规则
- 纯时间函数:仅使用
seek(t)。没有Math.random、没有定时器、没有 CSS 过渡、没有requestAnimationFrame(在渲染模式下)、没有帧间状态。 - 打开
-view.jpg预览;全分辨率图像仅作为某个细节的--crop。图像用于外观检查;机械检查依靠工具的数字(node tools/check.mjs --film=<film>:seek 扫描、确定性、字体 px、布局 lint)。 - 上下文是成本,而对话轮次会放大它:一次 300k 的轮次成本相当于三次 100k 的轮次,而最近三分之二的消息只携带了一个工具。在一条消息中发送某个步骤的每次独立读取、搜索和编辑。工具是运行的,而不是阅读的(
--help给出用法);使用 Edit 进行编辑,永远不要重写整个文件;长时间运行的命令在后台执行,你等待通知,不要使用sleep或轮询循环。 - 另一部电影的源代码不是模板:电影之间共享 3–16% 的代码。查找你需要的那个函数(Grep,或带偏移/限制的 Read),并保持其
film.js未打开。 - 状态存在于文件中:
brief/decisions.md、references/sources.md、<shotlist>、docs/review_log.md。项目在 250k 时自动压缩,因此仅保留在对话中的事实可能在影片中途消失。 - 密码仅来自
.env。不要打印、记录或粘贴密钥。 - 每个品牌一个会话:引擎、合成器和导出管道被重用,而不是重建。