夜雨聆风学习资料网

ARTICLE · 1207605

亲测!不装剪辑软件,我用 AI 写完了25分钟讲解视频

亲测!不装剪辑软件,我用 AI 写完了25分钟讲解视频
先给结论:这些竖屏视频,是我用一个 HTML 文件"写"出来的。同一份文案做了两套风格。下面把手艺和踩的坑都摊开讲。成品可以在公众号关联的视频号看到。关注我,回复:HyperFrames,获取开源仓库地址。

全文 1800 字,配 5 张实拍画面,读完约 8 分钟。中间有几段代码,是片段,不影响理解。

片子讲的是这么件事。

一个爸爸陪五岁闺女看动画片,看到一半出去回了个工作消息,回来孩子已经睡着了。第二天他想了半天,那一集讲的什么,一点印象都没有,只记得那条消息。

第一期视频,其他在视频号看到效果

20 秒,两个主持人,一问一答。

我没有拖过一条时间轴,也没有找过一帧素材。

01一个 HTML 文件,就是一条片子

工具叫 HyperFrames,HeyGen 开源的,口号就一句:写 HTML,出视频。

它干的事不神秘。你把整条片子写成一个网页,画面、出现时间、动画,全用 HTML 和 CSS 描述。然后它开一个无头浏览器,第 1 帧截一张,第 2 帧截一张,一直截到第 600 帧。最后把这些图交给 FFmpeg 编码成 MP4。

关键在"逐帧"这一步。换来的是确定性——同一份代码,跑一百次都是同样的 600 帧,像素级一致。录屏做不到,它会掉帧、会卡,换台机器结果就不一样了。

做系列内容的人会在意这个。片子能复制,能改,能批量。

02同一段话,两种气质

第一版叫「暗金电影」。近黑底,暖金光,标题用思源宋体压住。开头三秒,三条工作消息一条接一条涌进来,未读数从 1 冲到 99+,屏幕跟着轻轻抖,像手机在桌上震。

第二版是「像素街机」。夜空紫,16 位游戏调色板,对话框一个字一个字往外蹦,转场是马赛克,屏幕上偶尔飘一层雪花点。整件事被做成了一个游戏:顶上有条"生活"血条,回消息那一下掉一颗心。最后字幕弹出来——生活 -1。

文案一个字没动,说话的人一样,都是 20 秒 30 帧。差别只在怎么写。

同一个开场,左边暗金,右边像素:

顺手跑了下体积检测:

▪︎ 规格:两版都是 1080×1920、30fps、20.0 秒

▪︎ 码率:暗金电影 5.72 Mbps,像素街机 1.21 Mbps

▪︎ 体积:14.3 MB 对 3.0 MB

像素那版只有电影那版的 21%。没什么玄机,像素画大面积是纯色块,H.264 压起来毫不费力。

同一句结尾,左边暗金、右边像素(右下角那条血条已经掉了一格):

03几个必须我自己拍板的地方

这一版是 Opus 5.5 配合 HyperFrames 做的。写代码这件事,AI 基本包了。真正要我自己定的,是下面这几样。

像素字不是字体,是画出来的。

像素风死在字上的最多。用一套像素字体,中文缺字严重;用普通字体,糊成一团黑。

我的做法是:先拿小字号把字画到画布上,再把抗锯齿的边缘切掉——透明度大于 128 的算实心,其余全变透明。切完字就只剩硬方块了。然后补一圈右下方向的 1 像素描边,整体放大若干倍,交给浏览器的 image-rendering: pixelated。

出来就是没有一丝模糊的真像素字。不用装像素字体,不用联网,中英数符号一个处理法。

所有缓动都是阶梯,没有一条平滑曲线。

普通动画是一条平滑曲线,物体匀着滑过去。像素游戏不这样,它是一格一格跳的。

所以这一版里,几乎每条动画都写成了"分几步":标题出现走 6 步,星星移动走 40 步,小箭头闪一下是一步。全片找不到平滑曲线。

这个选择在代码里看不出来,但它决定了成片是有游戏感,还是像 PPT 加了点动效。

画面和声音是分开做的。

我查了一下成片,两个 MP4 里都没有音轨,纯画面。

画面归画面,声音归声音,各自做到上限,最后合。为什么这么拆?因为声音那条线,用的是另一套完全不同的 AI。

04声音是另一条线

播客那条线,我用豆包语音的「播客」。把写好的讲稿丢进去,出来的是一男一女真的在聊,不是一个人念稿。

我的配置固定两个音色,男主持大罗,女主持大猫。这套配置存下来跨会话复用,所以每期听感是连着的,听众不会听出"今天换人了"。

有几条规矩是我自己定的,比技术更影响成品。

讲稿逐字执行,不许加话也不许删。AI 生成对话时特别爱"贴心地"补几句过渡,听着顺,但会把事实讲歪。

不要片头音乐,不要音效,第一句就进对话。手机上刷到播客,前 3 秒决定他走不走。

语速中等。最后统一做一遍响度归一化,压到 −16 LUFS。不做这步,你的节目就比别人小声,用户得手动调音量,然后就划走了。

音频出来,再和画面合成,一条"AI 双人播客 + AI 配套视频"就齐了。

05想自己上手,卡在哪

先把话说清楚:这不是"输一句话出视频"。

现在要装 Node.js 22 以上和 FFmpeg,手上得有一份 HTML,时间轴得有人写对。

两年前卡在"我不会写代码",这个卡点基本被 AI 消掉了。我是把要什么画面、每一秒发生什么,一条条讲清楚,让 AI 写成 HTML 的。

还留在手里的有三件:知道自己想要什么气质,颜色和节奏选得对;能把画面切成"第几秒发生什么";愿意抽帧出来一张张看,检查有没有元素压到一起、有没有贴边。

抽帧这件事我已经做成习惯了。有一版像素风刚出来,字又粗又挤,放大倍数太大,扫描线也压得太重,整体糊成一片。后来字体从 Bold 换 Medium,放大倍数压下来,描边只留右下 1 像素,扫描线透明度降到 0.12,才看清。

这几步调整,AI 不会主动告诉你。它只会说"已经完成"。

06风格库的主要代码

HyperFrames 是开源框架,Apache 2.0,可以商用。仓库地址我放文末。

我这版工程长这样,一个 HTML 对应一条片子:

video_e01/├── tools/│   ├── cut_grid.py      九宫格原画 → 9 张透明表情图│   └── pixelate.py      透明图 → 72×72 像素头像├── e01_girl/            S01 暗金电影│   ├── index.html       整条片子的全部定义│   ├── assets/          char/ 表情图 · fonts/ 本地字体│   └── renders/         成片└── e01_girl_s02_pixel/  S02 像素街机(同结构)

风格库的核心是两套色彩令牌。换风格,本质就是换这几个变量:

/* S01 暗金电影 */:root{ --bg:#060606; --ink:#f4f1ea; --mute:#8d8981;       --gold:#d1a95e; --gold2:#f0cf8d; --red:#ff4b45; --tv:#7fd6ff; }/* S02 像素街机 */:root{ --bg:#13111f; --ink:#fff1e8;       --gold:#ffcc4d; --red:#ff3a5c; --blue:#5fcdff; --mute:#8b80a8; --k:#0b0a14; }

字幕这么排。一句台词带起止时间,谁说话谁放大,另一位压暗:

const CAPS = [  ["mao","公司拿到的,是<em>随时打断你生活的权利</em>。",0.25,2.95],  ["luo","上周,我陪我<em>五岁的闺女</em>看动画片。",3.15,5.95],  ["luo","看到一半,出去<em>回了个消息</em>,",6.1,8.5],  // …];const speak = (who,t)=>{  const other = who==="luo" ? "mao" : "luo";  tl.to("#"+who,   {scale:1.08, filter:"brightness(1)"   }, t);  tl.to("#"+other, {scale:0.92, filter:"brightness(.55)" }, t);};

像素字那套切抗锯齿的处理,核心就几行:

function hardEdge(ctx, W, H, outline){  const img = ctx.getImageData(0,0,W,H), p = img.data;  const on = new Uint8Array(W*H);  for (let i=0;i<W*H;i++){    if (p[i*4+3] > 128){ on[i]=1; p[i*4+3]=255; } else p[i*4+3]=0;  }  if (outline){ /* 向右下补 1px 描边 */ }  ctx.putImageData(img,0,0);}

像素角色不用图片,字符画写成矩阵,逐点画。这是那只小熊:

bear:{ c:{B:"#a8642f",D:"#5c3416",W:"#f5d1a4",o:"#0b0a14",e:"#0b0a14"}, m:[  ".oo....oo.","oBBo..oBBo","oBBBBBBBBo","oBeBBBBeBo","oBBWWWWBBo","oBBWDDWBBo",  ".oBBBBBBo.","oBBBBBBBBo","oBBBWWBBBo","oBBBWWBBBo",".oBBooBBo.",".ooo..ooo."]}

最后,把时间轴交给渲染器逐帧播放:

window.__timelines = window.__timelines || {};window.__timelines["main"] = tl;tl.seek(0);

这套风格库现在撑到了第五期正片。换个风格就是换一份 HTML,内容不用重做。下一步我打算把它拆成模板,下次换选题只改文案。

关注我,回复:HyperFrames,获取开源仓库地址。
THE END

相关学习资料