从代码生成的视频创建可编辑的 After Effects 项目
目标是创建一个动态设计师可以直接打开并像手工构建一样工作的项目。文本是真正的文本,路径是形状层,每个对象都是一个命名的预合成,摄像机是一个他们可以重新设置关键帧的 Null 对象。与此相反的是将渲染后的帧序列放入合成中,这种方式无法编辑,因此永远不要将其作为主要的动画交付。
该方法包含三个步骤:
- 从渲染器绘制时所使用的同一数据中导出场景。
- 将其写入
scene.json。 - 让 After Effects 通过运行生成的 ExtendScript 自行构建项目。
你永远不需要手动编写一个二进制 .aep 文件。
renderer data ──export──▶ scene.json + assets/ ──make_jsx.js──▶ build.jsx ──After Effects──▶ project.aep (+ check stills)
打包的脚本(位于 scripts/):
aelib.jsx:在 After Effects 内部运行的构建器。它读取场景并创建合成、图层、关键帧、蒙版、效果、遮罩、标记和音频,然后保存 .aep 文件和构建日志。make_jsx.js:node make_jsx.js [--portable] scene.json build.jsx。检查场景(缺少的资产、错误的父级、预合成顺序)并写入一个独立的build.jsx。使用--portable参数时,路径相对于build.jsx,因此文件夹可以压缩并在另一台计算机(包括 Windows)上运行。对于你交付的任何内容都请使用此参数。run_in_ae.sh:run_in_ae.sh build.jsx /abs/path/Project.aep [timeout]。在 macOS 上,在已安装的 After Effects 中运行构建,等待其完成,并打印日志。
在编写导出器之前,请阅读 references/scene-spec.md。它定义了每个字段、缓动、已检查的效果匹配名称和值范围,以及那些会浪费时间的陷阱。
工作流程
1. 盘点视频绘制了什么
阅读渲染器并列出屏幕上出现的所有内容及其运动方式:
- 世界或背景。
- 每个对象或文档。
- 每一段文本。
- 摄像机移动。
- 与词语或节拍同步的时刻。
- 视觉效果:颗粒、辉光、暗角、运动模糊、淡入淡出。
- 音频。
对于每一项,记下其数值来源(常量、几何函数、时序文件)。
2. 将每个元素映射到其 AE 原生形式
选择动态设计师会手工构建的形式:
| 在代码中 | 在 After Effects 中 |
|---|---|
| 在世界上移动的摄像机(平移、缩放、旋转) | 一个 CAMERA null。锚点 = 摄像机在世界坐标中看向的点。缩放 = 缩放。旋转 = 翻滚。位置 = 合成中心。将每个世界层父级关联到它。然后 screen = position + R·scale·(p − anchor),这与 Canvas 摄像机变换完全相同,因此世界层保持代码所使用的坐标。 |
| 手持抖动、冲击震动 | Null 对象位置和旋转上的表达式,由以其功能命名的 滑块控件 驱动(如“Handheld amount”、“Impact strength”) |
| 一个对象或文档(打印、纸张、卡片、书籍) | 其自己的 预合成,包含边框、照片、文本、接触阴影和一个“Dim”固态层。以 2 倍尺寸创作图层,并缩放至 50%。打开 折叠变换。在预合成图层上对掉落动画设置关键帧。 |
| 矢量路径(海岸线、标尺、圆形、线条) | 形状层,每个逻辑片段一个组,并命名 |
| 文本 | 文本层,包含真实字符串和 PostScript 字体名称。永远不要使用预先渲染的文本图像。 |
| 代码生成的位图(占位照片、纸张纹理) | 将其导出为 PNG/JPG 资产,命名使其易于替换(如“PHOTO — replace me”) |
| 随旁白逐字出现的文字 | 一个文本层,带有 reveal: { times: [...] }。构建器为每个词(在 AE 中测量)设置一个写入遮罩的关键帧,并且文本保持可编辑。 |
| 线条自身绘制 | Trim Paths end 关键帧 0→100 |
| 印章或猛击 | 缩放/不透明度关键帧,加上一个在摄像机冲击列表中的条目 |
| 主体聚焦 / 其它变暗 | 每个预合成内一个带有“保持透明度”的黑色“Dim”固态层,加上背景上方一个全屏的 Dim 固态层,并带有不透明度关键帧 |
| 胶片质感 | 命名的调整图层(如“LOOK — Soft glow”、“LOOK — Film grain”),一个带有羽化反向蒙版的暗角固态层,一个淡入淡出固态层,以及世界层上的合成运动模糊。全部命名以便于开关。 |
| 音频 | 分离的音频主干(语音、音乐/音效)作为音频层,加上旁白行作为 合成标记 |
3. 从数据源导出
向现有渲染器添加导出路径,而不是重新输入数字。例如,公开其内部接口(module.exports、--export 标志或导入其模块)并编写 export_ae.js / export_ae.py。它应生成 scene.json 和一个 assets/ 文件夹。这样 AE 项目和 MP4 就不会有偏差,并且在故事更改后重新导出一个命令即可。
匹配运动行为:
- 摄像机和其他曲线。 在关键时间点(保持开始和结束、着陆)设置关键帧,而不是每一帧。为每个关键帧赋予该点上曲线的真实速度,影响系数为 33.333%;这可以精确再现三次 Hermite 样条。如果某段运动在中间也发生了某些变化(如拉远缩放、对数空间缩放),则在运动的 ¼、½ 和 ¾ 处添加关键帧及其各自的导数。使用渲染器自己的摄像机函数数值计算导数。
- 符号速度。 旋转、缩放和不透明度的速度是有符号的。空间属性(位置、锚点)仅取绝对值。
- 逐帧关键帧 仅可用于真正不规律的事物,例如闪烁。其他一切应易于抓取和移动。
- 重新定时。 从渲染器使用的同一文件(例如
timings.json)读取时序,因此重新定时语音也会重新定时项目。
为打开项目的人着想:
- 为每个图层命名,使其表明其内容(如“Ink circle (draws on 'Kestrel Point')”、“Map dim (hero focus)”)。
- 为任何非显而易见的内容添加一行的
comment。 - 使用标签进行分组,并为摄像机 Null 赋予独特的标签。
- 旁白行放入合成标记。
4. 构建与检查
node <skill>/scripts/make_jsx.js --portable --quiet scene.json build.jsx # build.jsx 位于 assets/ 旁边
<skill>/scripts/run_in_ae.sh build.jsx "/abs/path/My Project.aep" 1500
- 先决条件(一次性,在 AE 中): 设置 → 脚本和表达式 → 启用“允许脚本写入文件和访问网络”。如果没有此设置,保存和构建日志会失败。如果运行器超时,此设置(或 AE 中打开的对话框)是常见原因;请要求用户检查。
- 它不会放弃未保存的工作。 如果打开的 AE 项目有未保存的更改,构建会停止并在日志中说明。永远不要以丢弃用户的项目为代价来解决此问题;请要求他们保存或关闭项目。对自动化构建使用
--quiet,以便消息进入日志而不是弹出阻止 AE 的对话框。对于你交付的build.jsx,请在没有--quiet的情况下重新生成,这样手动运行它的人会看到消息。 - 构建日志(
<Project>.build-log.txt)列出每个失败的图层、效果或属性。将任何问题视为场景中的错误,并在导出器中修复,而不是在 AE 中手动修改。 - 检查静态帧。 将
project.stills设置为 5–8 个关键时间点:一个与词语同步的时刻、一个中间下落动作、一个主体保持画面、标题。构建器会从主合成中渲染它们。它们会在保存后异步渲染,运行器会等待它们。它们是 16 位 PNG,ffmpeg 可能无法读取,可以使用sips -s format jpeg -Z 1920 in.png --out out.jpg查看。 - 并排比较 与原始渲染中同一时刻的帧。检查构图、哪个对象是主体、文本揭示是否与词语对齐,以及颜色和亮度。然后修复导出器并重新构建。AE 中的辉光比 Canvas 的“带有模糊的叠加屏幕”强得多,因此从高阈值(~200/255)和低强度(~0.2)开始。
如果此机器上没有安装 After Effects,或者编辑人员在另一台电脑上,请不要尝试启动它。交付便携式文件夹(build.jsx、assets/、scene.json、README)。他们通过 文件 → 脚本 → 运行脚本文件… 运行它,.aep 文件将保存在 build.jsx 旁边。README 必须告知他们先启用脚本文件写入设置,并且必须安装字体。
5. 交付
交付一个文件夹,包含:
<Name>.aepassets/build.jsx和scene.json,以便可以重建项目- 导出器脚本
- 一个简短的
README.md,说明如何:- 移动摄像机:在 CAMERA null 的锚点(看向的位置)和缩放(缩放)上设置关键帧
- 替换照片:在项目面板中,选择资产并使用文件 → 替换素材
- 重新定时一个词:拖动该图层的写入关键帧,或在更改时序后重新导出
- 切换质感图层
- 更改文本:双击它
- 必须安装哪些字体
向用户明确说明:
- 哪些是完全匹配的(布局、时间、关键帧)
- 哪些是近似匹配的(AE 的辉光、颗粒和颜色与 Canvas 合成略有不同)
- 你通过静态帧检查了什么,以及你没有检查什么(例如完整时长回放)
之前出过的问题
以下是上述约定背后的原因:
- 形状或文本图层上的阴影和模糊不会随摄像机缩放,因为其效果在变换后应用。对于世界空间的辉光和阴影,请使用带蒙版的固态层。
- 预合成在摄像机拉近时会变模糊。 通过打开折叠变换来解决,并以 2 倍尺寸进行创作。
- 羽化蒙版在固态层边缘被裁切。 将辉光固态层做得比辉光本身大得多。
- 字体必须是 PostScript 名称。 通过在 AE 中快速探测来检查未知字体:设置
textDocument.font并读回。 - ExtendScript 是 ES3,并且会误读链式三元运算符(
a ? b : c ? d : e):改用查找表或if/else。如果你更改了aelib.jsx,请先在一个小型场景(一个文本层、一个形状、一个预合成)上测试,然后再进行完整构建。