我的博客叫「星世纪」,用的是自己二改优化的「敬山月」主题。
过去它一直以截图和文字的形式存在:首页、关于、图库、文章、搜索,每个页面都挺好看,但看久了总觉得少了点“活气”。于是这个月我干了一件事——给博客做一支 61 秒的 showcase,把网站里的页面、动效和交互重新编排成一条片子。
先说结论:**AI 能很快把骨架搭起来,但一支片子好不好看,最后仍然要逐帧看、逐帧改。**
一、先让 video-shotcraft 把骨架搭起来
起点是 [video-shotcraft](https://vincentwei1021.github.io/video-shotcraft/)。它更像一套“镜头卡”参考库:转场、文字动效、页面推拉、胶囊切换,每一类都有实现思路和参数说明。
我先用 GPT 让这些镜头卡落成一个能跑的 Remotion 工程:分镜、`Sequence`、基础组件、时间轴都先搭出来。
技术栈很朴素:
- Remotion 4
- React 19 + TypeScript
- 1920 × 1080
- 30fps / 60fps 双版本
- Playwright 截图 + PIL 合成素材
- ffmpeg 合成音效与成片
选 Remotion 的原因也简单:**它的时间轴就是 React 代码**。网页截图、CSS 动画、3D transform、音效 cue,全都可以挂在同一个帧号上,改起来像改页面一样。
但骨架只是骨架。后面大部分时间,我都在和 AI 助手一起做一件事:把“能跑”改成“能看”。
二、16 个镜头,不是 16 张 PPT

成片一共 16 个 `Sequence`,对外编号是 S1–S11。
大致可以分成五段:
1. **开场**:涟漪、首页升降、关于页多层视差、近期文章聚光;
2. **文章**:文章详情、玻璃扫光、下滑到上一篇、上一篇主角卡;
3. **继续阅读**:下滑到卡片、三卡独立展示、回顶点击图库;
4. **图库与关于**:瀑布墙、回正到真实页面、文章分段归位;
5. **交互与收尾**:语言/登录/GitHub、胶囊切换、白主题搜索、全家福。
这里面没有一段是“录屏加速”。
比如文章详情的玻璃扫光,是把页面截图固定住,再用一条倾斜的高光带扫过;图库瀑布墙,是把 9 张图重新排成三列做纵向循环;关于我的文字,是把真实文章切成 15 段,先留空槽,再让段落一段段落回原位。
**页面是素材,不是背景。** 这是整支片子最重要的一个转变。
三、真正难的都是细节
1. 截图不是截完就能用
最早图库的截图里,有些图片只加载了一半。原因是逐元素截图时懒加载还没完成。
后来改成:先滚动整页触发加载,等所有图片 `complete`,再整页截图;图库干脆直接下载原图,统一转成 PNG,三列 3/3/3 重排。
继续阅读的三张卡也遇到过类似问题:目标文章本身的“继续阅读”是空的。最后的做法是单独截三张卡,再按原网格位置合成到整页截图里,S7B 则用独立舞台重新展示三张卡和边框聚光。
2. 转场要服务叙事,不是默认淡入淡出
一开始很多切点都走黑色淡出,看下来很碎。
后来把 S5→S5B、S5B→S6、S6→S7A、S7A→S7B 这些切点全部改成硬切;S7C→S8 的黑屏则查出来是瀑布墙图片写了 `from={1}`,第 0 帧根本没渲染。
这类问题很典型:**画面黑一下,不一定是转场参数,可能是素材第一帧就是空的。**
3. 倾斜角度要跟下一镜一致
S7C 到 S8 的过渡,最早是整页向左上飞走,角度很夸张。
后来改成:`perspective(1000px)` + `rotateX(20deg)`,和 S8 瀑布墙的倾角一致;页面只倾斜、不位移,停在倾斜状态里淡出。这样两镜之间才像“同一空间里的接力”,而不是两张图各演各的。
4. 文字动效要对齐真实界面
S9C 的搜索镜头,前半段一直不顺。
最后拆成几件事:
- 打开搜索框后先输入一个空格,让 placeholder 消失,截出一张真正的空白输入框;
- 在 Remotion 里按真实输入框的字号、位置、行高叠加「主题」,并做裁切容器,保证文字不会跑出圆角;
- 输入完成后显示「↵ Enter」键帽,按下再开始检索;
- 检索用三列滚轮,`easeOutQuint` 从快到慢,快停住时结果框再向下展开;
- 滚轮只占结果区,底部「选择 / 确认 / 关闭」始终露出来。
“模拟输入”不是打个字就行,**文字的位置、字号、基线,差 1px 都会露馅。**
5. 60fps 不是勾一个选项
Remotion 工程默认 30fps。直接把 composition 改成 60,所有动画会快一倍。
所以 60fps 版本是单独做的:
- 新增 `ShfmerShowcase60`,`fps=60`,总帧数 ×2;
- 用一个 `TimeScaleProvider` 把组件时间轴压回 30fps 语义;
- 组件用半帧步长求值,等于每一帧都重新算一次位置;
- 音效 cue、转场边界全部 ×2 重排。
核心代码很短:
```tsx
const TimeScaleContext = createContext(1);
export const useScaledFrame = () =>
useCurrentFrame() / useTimeScale();
export const useScaledFps = () =>
useVideoConfig().fps / useTimeScale();
```60fps 版本里 `scale = 2`,组件仍然按 30fps 的时间写,但每 0.5 帧采样一次,所以动作是真的更细,不是插帧。
6. 声音也是画面的一部分
基础音效是用 Python 合成的 WAV:点击、键盘、回车、卡片 pop、胶囊 tick、结尾 chime。
中间也踩过坑:页面缩放时铺 whoosh,听起来像一直在“chuchu”;装饰性 pop 太多,又会变成“波波”。最后只保留和动作严格对应的声音:真实点击才响 click,输入才响 type,滚轮才响 tick。
音乐还没加,留给自己后面配。
四、AI 在里面的角色
这支片子前半段的骨架,是 GPT 按 video-shotcraft 的镜头卡搭出来的;后半段基本是和 AI 编程助手一起逐帧改。
AI 最擅长的部分:
- 快速生成 Remotion 组件和分镜结构;
- 把“这个页面要推近、要倾斜、要出边框”翻译成 CSS / SVG / 插值;
- 批量改时间轴、音效 cue、字号和坐标;
- 用 `remotion still` 反复截帧做对照。
但 AI 不擅长判断:
- 这一刀该不该硬切;
- 这个镜头是该停 0.5 秒还是 1.5 秒;
- 这个音效是不是“对”,还是只是“有”;
- 这个动效是高级,还是只是复杂。
所以真正的流程是:**AI 写,人看;人提意见,AI 再改。** 一帧一帧截,一版一版比。
五、最后的数据
- 画幅:1920 × 1080
- 镜头:16 个 `Sequence`
- 时长:61.33 秒
- 30fps:1840 帧,约 39.6MB
- 60fps:3680 帧,约 46.7MB
- 编码:H.264 + AAC
- 音效:基础 SFX,暂无音乐
跳转>>>--演示视频--
六、如果重来一次
我会先做三件事,再让 AI 写代码:
1. **先写镜头表**:每个镜头从哪开始、停多久、下一刀怎么接;
2. **先截素材**:所有页面、卡片、文章段落先截干净,确认没有懒加载;
3. **先定声音**:哪些动作必须有声,哪些地方宁可静音。
而不是反过来——先让 AI 生成一堆动画,再逐个删。
这支片子谈不上多厉害,但它确实把「星世纪」从一堆静态页面,变成了一段可以拿出去给人看的东西。对我来说,这就够了。
相关链接:
- 博客:[https://www.shfmer.top]
- video-shotcraft:[https://vincentwei1021.github.io/video-shotcraft/]
- GitHub:[https://github.com/RanZhiYi]