SuperAPI AI Directory

chengfeng-export-talking-head

Frontend & websites

View repository

Updated 10-15 16:42

About this skill

Export (finished video)

This is the last link in the chain, and the only place in the whole product that actually draws pixels.

Everything before it is annotation: the ledger records "which words play", subtitles record "what is written on screen", visuals record "what layer is overlaid", and the preview assembles these three in real time to show the user,without writing to disk. Export burns them into one file.

需要   edit-list.json(必须)、subtitles.json、visuals.json + modules/
产出   成片.mp4

Prerequisite tools: the machine has Google Chrome(used to draw subtitles and animations into images) and ffmpeg. A missing Chrome will produce an explicit error; do not try to work around it—without it there is no subtitle layer or animation layer.

First read and execute the business Skill's stage contract in the "Conclusion Level" section.Export does not enter the editing state machine: it does not modify any project files, does not perform CAS writes, and does not advance stage; the output is a new file, and rerunning overwrites it. So it does not need a confirmation card.

0. Always do the Runtime precheck first

Precisely obtain from Codex's enabled Plugin list the chengfeng-videocut of source.path。 SKILL_DIR is not a variable Codex guarantees to inject; it is forbidden to rely on it, hardcode development machine paths, or use find to guess the installation directory:

PLUGIN_ROOT="$(codex plugin list --json | node -e 'let s=""; process.stdin.on("data", c => s += c); process.stdin.on("end", () => { const rows = JSON.parse(s).installed || []; const hit = rows.filter(x => x.enabled && x.name === "chengfeng-videocut" && x.source && x.source.path); if (hit.length !== 1) process.exit(1); process.stdout.write(hit[0].source.path); });')"
test -n "$PLUGIN_ROOT" && test -f "$PLUGIN_ROOT/.codex-plugin/plugin.json" || { echo "chengfeng-videocut enabled plugin root unavailable" >&2; exit 1; }
ENSURE="$PLUGIN_ROOT/scripts/ensure-runtime.cjs"
VC="$PLUGIN_ROOT/scripts/videocut-cli.cjs"

node "$ENSURE" --install-if-missing --json
  • ready: continue this Skill.
  • missing: the script only prompts once "installing from GitHub Release", and automatically resumes after verification completes.
  • runtime_unhealthy, installation failure, or doctor failure after installation: report structured diagnostics and stop. Stop means stop: it is forbidden to continue the process with a self-made review page, player, timeline, or any substitute interface. Any output made while the product is unavailable is untrustworthy (real case: when Runtime was missing, the Agent hand-built a "screening station" web page, and its review decisions were completely incompatible with the product's ledger format, so the user had to do it all over again). The only correct action is: give the user the structured diagnostics, and guide them to install or report an Issue.
  • During the precheck stage, it is forbidden to start services, open Studio, or create projects.

For the detailed protocol, see Runtime and Product Contract。

Command

node "$VC" export <project> --dry-run --json          # 先看计划,不编码
node "$VC" export <project> --json                    # 出成片(默认 2 倍、源帧率)
node "$VC" export <project> --out /path/成片.mp4 --json
node "$VC" export <project> --scale 1 --json          # 只要源尺寸
node "$VC" export <project> --keep-work --json        # 留下中间片和逐帧 PNG,供排查

Two steps, do not run only the second step

① --dry-run 先报计划    片长、帧数、字幕屏数、画面层数、推近段数、输出尺寸
                       念给用户听。数字不对就是上游不对,编码十分钟不会修好它
② 真跑                 assemble → overlay → compose → verify 四段进度

--dry-run in warnings must be relayed verbatim. It reports only one kind of thing:the words of certain subtitle screens or visual layers have already been cut out, so they will not appear in the finished video. This is something upstream must decide, not something export should swallow on the user's behalf.

Clarity: the source video is the ceiling; look at the source before talking about upscaling

Before exporting, take a look at the source resolution (--dry-run the source field has it):

源宽 ≥2560(Retina 原生录屏)  → --scale 1,输出就是原生像素,这是最好的情况
源宽 <1920(如 960×720)      → 先停一下:问用户有没有同一次录制的高清导出。
                              录屏工具常常能把同一次录制重新导出成 3 倍分辨率,
                              换源比任何后期都管用(见下节)。确实没有 → --scale 2

--scale 2 Why it is useful for low-resolution sources: enlarging the negative will not make it clearer, butsubtitles and animations are redrawn at the output size—these are the two things the viewer is actually reading; and when the platform compresses it again, the larger image also gets a higher bitrate.

Do not adjust --fps。 for the sake of "more clarity"; the frame rate follows the source video; changing it will only make the animation's sampling and screen recording mismatch.

Switching source: when the user provides a high-definition version of the same recording

This is not part of the export flow—the export itself is always read-only. Swapping the source is an independent material operation that happens only after the user explicitly gives the go-ahead; once it is done, come back and export normally.

First determine whether it is the same one(the first two are already hard enough):

ffprobe -v error -show_entries format=duration -of csv=p=0 <两个文件>   # 时长精确到毫秒相同
ffmpeg -v error -i <文件> -map 0:a:0 -c copy -f md5 -                  # 音频流逐位相同
# 再抽两三帧对比画面内容,眼睛确认

Audio bit-for-bit identical = timeline identical: the word-by-word script, the ledger, the subtitles, and the visual layers are all bound to word ids, so not a single one needs to be touched. This is exactly the redemption of "bind to words, not to seconds" in the matter of swapping the source.

Four steps to swap the source(actually walked through once on 2026-07-29; step ③ was missed at the time, and the editing preview immediately reported "generation failed"—fingerprint records are in more than one place, so grep the old fingerprint to find them all before acting):

① 换文件      input/source.mp4 和 uploads/source.mp4 是硬链接对 ——
              rm 两个,cp 新文件到 input/,再 ln 回 uploads/
② 更新指纹    project.json 的 source.sha256 改成新文件的
③ 再查一处    workbench.json 的 sourceSha256 也记着源片指纹,
              剪辑预览管道校验的恰恰是这本 —— 漏了它,预览拒绝生成
              (这是产品的正确行为:指纹对不上宁可失败,不拿旧预览冒充)
④ 重导        --scale 1 —— 换源就是为了原生像素,别再放大

The safe approach:grep -rl <旧指纹前8位> <项目目录> --include="*.json", every place listed must be handled (cache records such as preview-edited/current.json will be recalculated automatically, no need to change them by hand).

If the audio is different (re-recorded, trimmed, different duration), then it isnot a source swap, it is a new project: the word-by-word script must be re-transcribed, and all annotations are void. Don't force-fit it.

Acceptance: three things, and if even one is missing it does not count as export complete

① 命令成功返回        产品自己数成片的尺寸、帧数、音轨,和计划逐项比。
                     对不上就是 readback_mismatch 报错,文件留在盘上当证据,
                     不算导出完成
② 抽帧看像素          从成片里抽帧,用眼睛看。至少覆盖:一个推近段、
                     一个整屏动画段、一个只有字幕的段、一个层与层的边界
③ 人耳听感            没人真的听过,一律记 human listening UNVERIFIED

② Do not substitute preview screenshots.Preview and the final cut are two rendering paths, and what acceptance needs to check is precisely whether they match— taking the preview image as evidence of the final cut is equivalent to treating the very thing to be verified as a premise.

To judge a push-in, look for discriminating landmarks; overall impressions deceive(actually stepped in this on 2026-07-29): after a 1.6x push-in, the screen page still looks like "a whole page", and on the thumbnail it is almost indistinguishable from the full view—I once misjudged a correct push-in frame as "the push-in was lost", wasted half an hour chasing it, and re-exported twice. The correct way to judge is to look forevidence that only cropping can cause: elements cropped in half (a bubble broken off in the middle), edge elements that disappear (sidebars, title bars). Compare with the same-moment frame from the source video and the case is settled at a glance.

To extract frames, just use ffmpeg:

ffmpeg -v error -ss 8.84 -i 成片.mp4 -frames:v 1 -y frame.png

Where to look when something goes wrong

--keep-work will leave three things under the project's .chengfeng-videocut/export/ , and they directly separate out "which half is wrong":

assembled.mkv    只有剪辑,没有任何盖的东西。它错 = 账本或切片错
overlay/*.png    只有盖的东西,透明底。它错 = 字幕样式或模块错
spans/*.mp4      合成后的分段。它错 = 推近或对齐错

Comparison table:

成片没有字幕/动画       overlay PNG 是不是全透明?模块是不是没答应 seek?
动画停在第一帧          模块没实现 seek,或者 GSAP 时间线没 paused
画面整块白             模块少了 `:root { color-scheme: dark }`
推近的框歪了            模块的 viewBox 和层的 zoom 不是同一组数
成片比计划短            某个 span 帧数不够,看 compose 阶段的报错
层边界闪一小段原片      overlay 截图陈旧(帧标记验证失效)。产品靠页面顶部的
                      帧标记条自证每张截图属于哪一帧;若复发,先确认 overlay
                      PNG 顶部有标记条、compose 有裁掉它的 crop
找不到 Chrome          装 Google Chrome,别改成别的渲染路径

What is not allowed

  • Do not say "export succeeded" as "acceptance passed"—the command returning success only means the product matches itself, not that the picture matches
  • Do not use preview screenshots, the DOM, or logs in place of frame extraction from the final cut
  • Do not report human listening PASS when no one has listened
  • Do not modify project files (change subtitles, delete layers, touch the ledger) just to make the export run. Export is read-only, it does not write
  • Do not do upstream work inside the export: if subtitles are missing, go write subtitles; if visuals are missing, go make visuals; don't temporarily slap one together in this section