- name
- motion-graphics
- description
- 要在视频上加一段动效图形时用:下横栏(姓名职务)、关键词字幕、大数字与图表、标注与引导、品牌贴片与片尾、倒计时与进度。不选模板,按规则写一个自包含的 HTML 画面(时间的纯函数),打包成代码包导入后放上时间线。只加静态文字、贴纸或已有的文字动画预设时不用;整条成片的规划看「从简报到成片」。
- version
- 1.0.0
# 动效图形
一段动效图形就是**一个按时间 seek 的纯函数画面**:给它第 t 秒,它画出第 t 秒该有的样子。不从模板库里挑,而是按本 skill 的规则把骨架的三个槽填上:结构(有哪些元素)、布局(放在哪)、动效(每个元素怎么进、停、出)。同一份槽换一行布局就是竖版,换三个颜色 token 就是另一套皮肤。顺序:
1. 定类别、时长、画幅与合成方式(第 1 节)。
2. 读骨架与一个最接近的范例(第 2 节)。
3. 按语法填三个槽:结构 → 布局 → 动效,再套时间包络与颜色(第 3 节)。
4. 自检:lint、抽帧、换长文案(第 4 节)。
5. 打包导入,放上时间线,对齐旁白(第 5 节)。
6. 验收(第 6 节)。
## 1. 定类别与时长
四类图形与它们的节奏;时长是目标,由旁白节点与可读性决定:
| 类别 | 用途 | 时长 | 要点 |
| --- | --- | --- | --- |
| 下横栏 | 姓名职务、来源、地点 | 3–4 s | 说话人开口后 0.5 s 内出现;左下或右下安全区 |
| 关键词 | 强调一句话里的一个词、一句口号 | 1.5–3 s | 跟旁白里那个词同时弹出;停留够读两遍 |
| 数据 | 一个数字、一条趋势、几项对比 | 3–5 s | 数字 count-up 1–1.6 s,结论句在数字之后 |
| 品牌贴片 | 标志进场、片尾、合作标识 | 2–3 s | 标志最后一个到位(lock),其余元素先就位 |
- **可读停留**:任何带文字的元素,入场结束到出场开始至少 1.2 s;一句话以上的文案 ≥ 2 s。
- **合成方式**:叠在视频上的图形用透明根(`alpha: true`),只画元素不画底;全画幅(片头、片尾、纯图形镜头)才给根上底色(`alpha: false`)。
- **画幅**:按视频的画幅写,16:9 用 1920×1080,9:16 用 1080×1920,1:1 用 1080×1080;帧率与视频一致(通常 30)。
- 画面里的事实(数字、姓名、引语)只用用户给的,不编;不用未经授权的商标与形象。
## 2. 骨架与范例
- 骨架:用 `skills_read` 读本 skill 的 `references/scaffold.md`,里面是完整可运行的单文件 HTML,三个槽用 `/* slot:layout */`(`<style>` 末尾的 CSS)、`<!-- slot:scene -->`(`<section id="scene">` 里的 HTML)、`/* slot:motion */`(`renderScene(time)` 里统一出场那行之后的代码)标出;其余部分(根元素属性、辅助函数、可 seek 的时间线、`window.__timelines`、`window.__GRAPHICS_QA__`)**原样保留**,不改。
- 范例在本 skill 的 `exemplars/<id>/16x9.html` 与 `9x16.html`(会话内按路径取;外部 Agent 的副本里没有这些文件,骨架加语法已经够写),每个只是填好槽的骨架,横竖两版只差布局槽:
| id | 类别 | 展示的动词 |
| --- | --- | --- |
| `lower-third` | 下横栏 | slide 错峰、backOut 弹出 |
| `big-number` | 数据 | count-up、scaleX sweep |
| `keyword-caption` | 关键词 | token 弹出换色、描线 |
| `callout-pin` | 标注 | pulse、path 描线、clip unfold |
| `logo-sting` | 品牌贴片 | 多块汇聚、lock、rise |
读一个最接近的范例就够,不必全读。范例的文案、颜色与布局数值都只是示例,按本次需求换。
## 3. 填三个槽
动词、角色词汇、位置族、安全区、幅度与颜色的完整表:用 `skills_read` 读本 skill 的 `references/grammar.md`。填槽的顺序:
**结构槽**:先写元素清单,一个图形 2–6 个可动元素。每个元素一个角色(mark、headline、label、card、rail、node、badge、chip、note…),用 `id` 命名;主文案标 `data-copy-primary`、次文案标 `data-copy-secondary`,文字容器加 `class="copy"`。常用组合:`mark + headline + tagline`(品牌)、`name + role + org`(下横栏)、`value + unit + takeaway`(数据)、`label + track + state`(进度)、`headline + items[3–4] + active`(列表)、`anchor + line + label`(标注)。
**布局槽**:选一个位置族(lower-safe、centered、top-rail、side-rail、split、grid、cluster、radial、corner、full-frame-transparent),写绝对定位的像素值。安全区:16:9 左右 ≥ 70 px、上下 ≥ 100 px;9:16 左右 ≥ 60 px、上 ≥ 180 px、下 ≥ 230 px(避开评论与操作栏)。字号:说明 15–18 px,次级 20–24 px,主标题 42 px,大数字 68–80 px。文案容器一定要有 `max-width`,长文案靠省略号而不是溢出。竖版只改这一段:横向 grid 改纵向,卡片宽 ≈ 画布宽 − 2×边距,文字块顶对齐。
**动效槽**:每个元素一个时间窗 `range(time, start, end)` 配一个缓动与 1–2 个属性:位移配 easeOut,弹出配 backOut,描线与出场配 easeInOut。写法固定为 `prop: (1 - p) * 幅度`、`scale: 起点 + (1 - 起点) * p`、`opacity: p`。幅度:元素级位移 30–120 px,画外面板 340–560 px,rotate ≤ 25°,弹出的 scale 起点 0.2–0.45,容器 settle 的起点 0.75–0.95。同一元素不同时 slide 又 pop。
**时间包络**(默认 4 s,其他时长按比例缩放入场段,出场固定):
| 项 | 规则 |
| --- | --- |
| 第一元素 | 0.02–0.05 s 起步,不从 0 开始 |
| 单元素窗口 | 0.5–0.8 s(描线 0.6–1.0 s,count-up 1.0–1.6 s) |
| 错峰 | 相邻元素起点相差 0.1–0.4 s;同类元素 stagger 0.1–0.3 s |
| 入场结束 | 最后一个入场在总时长一半之前结束(4 s 时 ≤ 2.2 s) |
| 停留 | 入场结束到出场开始 ≥ 1.2 s;停留期可以有 pulse(±2%)或连续计数 |
| 统一出场 | 骨架已写好:结束前 0.62 s 到 0.05 s,整个 `#scene` 用 easeInOut 淡出;不另写每个元素的出场 |
**颜色**:只用 `--ink`(深色、文字)、`--panel`(浅底)、`--accent`(强调)三个 token,半透明用 `color-mix(in srgb, var(--ink) N%, transparent)`。用户或成片的风格说明里有色板时按它填;没有时从 `references/grammar.md` 的调色里挑一组。字体只用骨架的系统字体栈,它覆盖中日韩与拉丁字符;不引外部字体。
## 4. 自检
写完先检查,再导入:
- **lint**:有命令行环境时跑 `node <skill 目录>/scripts/build-bundle.mjs --html <index.html> --out <目录> --lint-only`,它核对根元素属性、统一出场、停留时长、时间窗范围、无外链与无随机、三个 token、`.copy` 与 `data-copy-primary`;加 `--verify` 时用 Electron 实际 seek 五个时刻截图,检查确定性、透明根、文案在安全区内、换长文案后不溢出。没有命令行环境时按同一份规则自己对照一遍(规则列在 `references/grammar.md` 末尾)。
- **抽帧看**:导入后用 compositions_preview 在 0 s、入场结束、停留中点、结束前 0.3 s 各抽一帧看:元素都在安全区内、文字不溢出、停留帧上所有文字可读、末帧已淡出。
- **换文案**:`__GRAPHICS_QA__.setCopy('long')` 与 `setCopy('cjk')` 对应的情况要能放下:成片语言的真实文案长度和一句很长的备选都试一次。
- 不通过就改槽,不改骨架;改完重新 lint。
## 5. 导入与上时间线
- **打包**:有命令行环境时用 `build-bundle.mjs --html … --out … --bundle-id <图形名>-<画幅>`(不带 `--lint-only`;横竖两版要给不同的 bundle-id)产出 `<out>/1/`(目录名是 revision,不给 `--revision` 时为 `1`):`index.html`、`bundle.manifest.json`、`files.manifest.json` 等,再把这个目录交给 compositions_import。没有命令行环境时直接把 `index.html` 以内联文件交给 compositions_import,由它计算哈希、写清单并做同样的校验。
- **导入即上时间线**:compositions_import 默认验证、烘焙,并把图形放到时间线上:从 0 s 开始、铺满画布、放在最上面的视觉轨(那条轨在这段时间被占着或锁着时新建一条)。它返回素材 id、尺寸、时长、是否透明,以及片段的 itemId 与 trackId。只想登记素材、先不放时,传 `register: true`。
- **对齐写在 `place` 上**:`place.at` 是时间线上的开始时间,`place.track` 指定轨道;导入时就给好,不必导入后再用 edits_apply 挪。开始时间对齐旁白里对应的节点:下横栏在说话人开口后 0.5 s 内;关键词与旁白里那个词同时;数据图形在旁白说到数字前 0.3 s 进。长度就是图形的时长,不拉伸。图形之间至少隔 0.5 s,不叠两个带文字的图形。
- **叠加层**与视频一起导出时不需要额外设置;全画幅图形当作一个镜头放。
- **改文案或改色**:改 HTML 里对应的槽,用新的 `--revision`(例如 `2`)重新打包,再用 compositions_import 导入并传 `replace: { itemId }`(上一版片段的 itemId):片段原地换成新版本,位置、轨道、不透明度、名字都保留。不传 `replace` 会在时间线上再放一段,两版叠在一起。新版本更短时片段跟着变短;更长且撞上后面的片段时导入会报错,先挪开后面的片段再换。不在时间线上改。换完版本、确认不再回退之后,用 assets_prune 列出没有引用的素材,带 `apply: true` 和旧版代码包的 assetId 删掉它(它的预渲染替身一起删);用户导入的素材不在此列。
## 6. 验收
- 对照用户要求:类别、文案、画幅、时长、位置、与旁白的对齐都按要求;事实只来自用户材料。
- 读回:videos_inspect 核对图形实例的起止时间与旁白节点的差值;抽帧看过的时刻写「看过」,没看的写没看。
- 报告分三栏:**量出来的**(时长、起止时刻、安全区边距)、**看过的**(抽过帧的时刻与看到的内容)、**要人看的**(动效快慢是否合适、颜色与成片是否搭)。lint 与 `--verify` 的结果原样附上,跳过的检查写明。
GitHub에서 보기