一篇关于在 TRAE Work 中与 AI 协作,将视频项目中的静态角色图片替换为完全程序化生成的 SVG 人物,并根据文章内容主题动态切换服装、配饰、道具与配色方案的完整记录。
起因:两个绕不开的问题
retro-anime-video 是我维护的一个 Skill,用来生成 90 年代日漫风格的知识讲解视频。它的原始设计很简单——通过 Python 脚本预生成角色 PNG 图片(蜡笔小新等知名 IP 形象),再丢进 Remotion 渲染成视频。这套方案跑了大半年,一直相安无事,直到两个问题越来越刺眼。
第一个是版权。蜡笔小新是臼井仪人工作室的角色,直接拿来用在视频里,严格来说是侵权。做个人项目无所谓,但一旦想对外发布或商业化,这就是一颗定时炸弹。
第二个更隐蔽,也更致命——主题脱节。无论视频讲的是大模型、金融理财还是健康养生,画面里站着的永远是同一个红衣黄裤的小男孩。观众看第一集觉得有趣,看第五集就开始出戏,因为角色和内容之间没有任何关联。
上图是优化前的标题场景,角色是预渲染的蜡笔小新 PNG 图片,无论视频内容是什么,角色的外观都完全相同。
对比场景也是一样,角色无法根据"传统 vs TRAE"的对比内容做任何外观适配。
我需要一套完全不同的方案:不引用任何外部图片,用代码画出人物,并且让人物的外观跟着视频内容变。
对话开始:向 AI 提出需求
我在 TRAE Work 里打开了 retro-anime-video 项目,给 AI 发了第一条指令:
我:深度优化 Skills:关于人物的渲染,不再使用 PNG,而是改为 SVG 程序化生成,根据文章主题内容来生成人物;
这条指令包含三个关键约束:弃用 PNG、改用 SVG 程序化生成、根据文章主题动态匹配人物外观。AI 收到后,没有急着写代码,而是先分析了整个项目的架构,定位到三个需要修改的核心文件:
CustomCharacter.tsx— SVG 渲染引擎,负责用路径画出人物ContentAwareDecor.tsx— 内容分析引擎,负责从文本中提取主题CharacterHost.tsx— 桥接层,把角色组件接入 Remotion 场景
接下来,AI 开始逐一实现这些模块。
系统架构设计
AI 设计的数据流很清晰:场景文本先经过关键词匹配识别主题,主题映射到人物配置(服装、配饰、道具、发型、配色),配置再驱动 SVG 渲染引擎画出完整人物。
三个模块各自独立,职责分明。ContentAwareDecor 只管分析文本输出主题,CustomCharacter 只管根据配置画 SVG,CharacterHost 把两者粘合到 Remotion 的场景系统里。这种解耦意味着以后扩展新主题,只需要加一行配置和一组关键词,不用动渲染引擎。
内容分析引擎:让 AI 听懂文章在说什么
AI 首先实现的是内容分析引擎。思路很直接——关键词匹配。每个主题维护一组中英文关键词,文本里命中任意一个,就算这个主题命中。
const THEME_KEYWORDS: Record<string, string[]> = {
ai_model: ['模型', '开源', '参数', '训练', '推理', '大模型', 'LLM',
'Kimi', 'K3', 'GPT', 'Claude', 'GLM', 'Moonshot', '月之暗面',
'AGI', 'Agent', '智能体', '多模态', '视觉理解'],
tech: ['技术', '代码', '程序', '数据', '算法', 'Python',
'transformers', '核心', '功能', '实战', '优化', '延迟', '吞吐'],
knowledge: ['知识', '学习', '什么是', '总结', '概念', '原理', '理解'],
finance: ['金融', '经济', '市场', '股票', '基金', '理财', '利率'],
// ... 共 19 个主题
};
匹配函数本身只有十几行:
export const analyzeContentThemes = (text: string): string[] => {
const matchedThemes: string[] = [];
const lowerText = text.toLowerCase();
for (const [theme, keywords] of Object.entries(THEME_KEYWORDS)) {
for (const kw of keywords) {
if (lowerText.includes(kw.toLowerCase())) {
if (!matchedThemes.includes(theme)) {
matchedThemes.push(theme);
}
break;
}
}
}
return matchedThemes;
};
一段文本可能同时命中多个主题。比如"Kimi K3 是月之暗面发布的开源大模型"这句话,同时命中 ai_model(因为"Kimi""K3"“月之暗面”“开源”“大模型”)和 tech(因为"模型"也在 tech 的关键词列表里)。AI 设计了一个优先级数组来处理这种情况:
const THEME_PRIORITY = [
'ai_model', 'tech', 'hardware',
'knowledge',
'finance', 'benchmark', 'value',
'space', 'nature', 'health',
'music', 'energy', 'success',
'emotion', 'communication',
'time', 'journey', 'idea',
'structure', 'growth',
];
AI 模型类主题排在最前面,因为这类内容最需要精准的角色匹配——讲大模型的视频如果角色穿的是运动服,违和感太强了。
主题到人物的映射:19 套外观配置
分析出主题后,需要把它转化成具体的人物外观。AI 设计了一个 CharacterConfig 数据结构,定义了五个维度的外观属性:
type ClothingType = 'hoodie' | 'sweater_vest' | 'suit' | 'tshirt'
| 'lab_coat' | 'jacket' | 'sporty' | 'cardigan' | 'default';
type AccessoryType = 'glasses' | 'reading_glasses' | 'goggles' | 'headphones'
| 'headband' | 'medal' | 'watch' | 'bracelet' | 'none';
type PropType = 'tablet' | 'book' | 'chart' | 'dumbbell' | 'telescope'
| 'microphone' | 'trophy' | 'compass' | 'speech_bubble' | 'none';
interface CharacterConfig {
clothing: ClothingType;
accessory: AccessoryType;
prop: PropType;
hair: HairStyle;
pattern: PatternType;
clothColor: string;
accentColor: string;
hairColor: string;
}
然后是一张 19 行的映射表,每行对应一个主题:
| 主题 | 服装 | 配饰 | 道具 | 适用场景 |
|---|---|---|---|---|
| ai_model | 连帽衫 | 眼镜 | 平板 | 大模型介绍、AI 产品发布 |
| tech | 连帽衫 | 眼镜 | 平板 | 技术教程、编程实战 |
| knowledge | 毛衣背心 | 阅读眼镜 | 书本 | 知识科普、概念解释 |
| finance | 西装 | 手表 | 图表 | 金融、经济、市场 |
| space | 实验服 | 护目镜 | 望远镜 | 太空、宇宙、星辰 |
| nature | 运动T恤 | 发带 | 哑铃 | 自然、生态、环境 |
| music | 夹克 | 耳机 | 麦克风 | 音乐、旋律、节奏 |
| success | 运动外套 | 奖牌 | 奖杯 | 超越、登顶、突破 |
映射表里的每个条目就是一行配置。科技主题对应的配置如下:
tech: {
clothing: 'hoodie', accessory: 'glasses', prop: 'tablet',
hair: 'messy', pattern: 'circuit',
clothColor: INK.indigo, accentColor: INK.blue, hairColor: INK.dark,
},
getCharacterConfig 函数把分析和映射串联起来,返回最终的人物配置:
export const getCharacterConfig = (content: string): CharacterConfig => {
const themes = analyzeContentThemes(content);
if (themes.length === 0) return DEFAULT_CONFIG;
for (const theme of THEME_PRIORITY) {
if (themes.includes(theme)) {
return THEME_CHARACTER_MAP[theme] || DEFAULT_CONFIG;
}
}
return DEFAULT_CONFIG;
};
SVG 渲染引擎:用代码画出手绘风格的人物
这是整个系统最硬核的部分,AI 在 CustomCharacter.tsx 里写了约 1300 行代码。
手绘质感的秘密:种子随机抖动
SVG 路径画出来的线条天然过于"完美"——数学上精确的圆和直线,看起来像 CAD 制图,不像手绘。AI 的解决方案是引入种子随机数,给每个路径点加一点抖动:
const seededRandom = (seed: number): number => {
const x = Math.sin(seed * 12.9898 + 78.233) * 43758.5453;
return x - Math.floor(x);
};
const jitter = (seed: number, amount: number): number => {
return (seededRandom(seed) - 0.5) * amount;
};
基于这两个函数,AI 实现了 wobblyCircle、wobblyLine、wobblyEllipse 三个基础路径生成器。以 wobblyCircle 为例,它把一个圆拆成 12 段,每段的半径加一点随机偏移,再用二次贝塞尔曲线连接,画出来的圆就带着手绘特有的不规则感。同一种子永远产生相同的抖动,所以每一帧渲染出来的人物是一致的,不会闪烁。
五个模块化渲染函数
人物被拆成五个独立的部分,每个部分由一个渲染函数负责:
renderClothing()— 9 种服装(连帽衫、毛衣背心、西装、T恤、实验服、夹克、运动外套、开衫、默认)renderHair()— 8 种发型(凌乱、整齐、尖刺、马尾、蓬松、时尚、波浪、默认)renderAccessory()— 9 种配饰(眼镜、阅读眼镜、护目镜、耳机、发带、奖牌、手表、手链、无)renderProp()— 10 种道具(平板、书本、图表、哑铃、望远镜、麦克风、奖杯、指南针、对话气泡、无)renderPattern()— 8 种图案(电路、条纹、圆点、叶子、音符、火焰、罗盘、无)
每种服装共用一个基础身体路径,然后在上面叠加特征元素。以连帽衫为例,AI 在基础身体上画了帽兜填充、帽兜内阴影、帽绳、帽绳末端的圆球、口袋轮廓和拉链线条——六层细节叠在一起,让连帽衫在低透明度下也能辨识。
主组件装配
CustomCharacter 组件把五个部分组装起来,还加了三种动画效果:
export const CustomCharacter: React.FC<CustomCharacterProps> = ({
pose, frame, scale = 1, accentColor, content = '',
}) => {
const config = React.useMemo(() => getCharacterConfig(content), [content]);
const breath = 1 + Math.sin(frame * 0.05) * 0.015; // 呼吸
const sway = Math.sin(frame * 0.04) * 3; // 摇摆
const entranceDur = 18;
const entranceP = Math.min(frame / entranceDur, 1); // 入场弹跳
const bounce = entranceP < 1
? 0.3 + 0.8 * entranceP + 0.1 * Math.sin(entranceP * Math.PI)
: 1;
return (
<svg width="320" height="420" viewBox="0 0 320 420">
{renderClothing(config, cx, cy, seed, sw, color)}
{renderPattern(config, cx, cy, seed, sw)}
{renderHair(config, cx, cy, seed, sw, color)}
{renderAccessory(config, cx, cy, seed, sw, color)}
{renderProp(config, cx, cy, seed, sw, color, handX, handY, pose)}
</svg>
);
};
组件支持 12 种姿势(pose),每种姿势定义不同的手臂角度和表情组合:wave(挥手)、explain(讲解)、think(思考)、write(书写)、jump(跳跃)等。
场景集成:让 9 个场景都传 content
9 个场景模板需要把各自的内容文本传给角色组件。AI 修改了每个场景文件中 CharacterHost 的调用,添加 content 属性:
// TitleCard.tsx
<CharacterHost
style={style}
pose={pose}
frame={frame}
position="center"
scale={1}
content={`${title} ${subtitle}`}
/>
每个场景传入的 content 内容不同:
| 场景 | 传入的 content | 角色位置 |
|---|---|---|
| TitleCard | 标题 + 副标题 | center |
| CodeBlockScene | 标题 + 代码 | bottom_left |
| QuoteScene | 引言 + 说话人 | bottom_right |
| ComparisonScene | 标题 + 左右标签 + 内容 | bottom_center |
以 Kimi K3 视频为例,标题是"Kimi K3 发布",副标题是"月之暗面旗舰开源大模型"。关键词"Kimi""K3"“月之暗面”“开源”"大模型"全部命中 ai_model 主题,角色自动穿戴连帽衫和眼镜、手持平板。
第一次验收:AI 给出了错误的结果
代码写完后,我让 AI 渲染视频看看效果:
我:提供一下最新 Skills 生成的视频内容
AI 渲染了视频并截取了帧。但我看了一眼就发现问题——画面里的角色虽然换了新衣服,但怎么看都还是之前那个蜡笔小新的 PNG 图片,不是 SVG 程序化生成的。我立刻指出了这个问题:
我:不对,这个版本不正确,已经没有 PNG,全是 SVG 动态生成的内容了
AI 重新检查了渲染管线,发现 CharacterHost.tsx 的 re-export 指向了旧的 PNG 组件,而不是新的 CustomCharacter。修正桥接层后重新渲染,这次出来的画面才是真正的 SVG 人物。
深度优化:从"几乎不可见"到"清晰可辨"
第一版 SVG 人物渲染出来后,问题比想象的严重——角色几乎看不见。服装填充透明度太低(只有 14.5%),道具尺寸太小(眼镜半径只有 12px),关键词覆盖不足导致很多场景退化为基础休闲装。AI 花了四轮优化才把效果拉上来。
第一轮:提升填充透明度。 服装填充从 ${clothColor}25(约 14.5%)提升到 ${clothColor}55(约 33%),关键元素填充提升到 ${clothColor}70(约 44%)。
第二轮:增大配饰和道具尺寸。 眼镜镜框半径从 12px 增加到 16px,平板宽度从 35px 增加到 48px,书本尺寸从 30x35px 增加到 40x48px。
第三轮:丰富服装细节。 连帽衫增加了帽兜内阴影、口袋轮廓和拉链线条;西装增加了口袋方巾;实验服增加了纽扣和侧口袋。
第四轮:扩展关键词覆盖。 ai_model 主题的关键词从 7 个扩展到 30 个,加入了"Kimi""K3"“GPT”“Claude”“GLM”“Moonshot”"月之暗面"等品牌名和产品名,确保主流 AI 内容都能命中。
最终效果
四轮优化后,我再次让 AI 渲染视频。这次的效果终于达到了预期——角色清晰可见,主题特征明确。
标题场景中,内容包含"Kimi K3 发布"和"月之暗面旗舰开源大模型",命中 ai_model 主题。角色穿戴蓝色连帽衫、圆形眼镜,手持平板电脑。人物由纯 SVG 路径绘制,没有任何外部图片。
数据展示场景中,角色佩戴眼镜、手持指示棒和平板,呈现科技讲解员形象。注意角色的服装颜色和配饰都与 AI 主题匹配。
知识科普场景中,内容包含"什么是"“概念”"原理"等关键词,角色穿戴蓝色连帽衫、佩戴眼镜,手持平板。
数据详情场景中,角色手持指示棒指向数据卡片,服装和配饰的细节都清晰可辨。
和优化前的 PNG 版本对比,变化是根本性的:
- 版权安全 — 所有人物元素由 SVG 代码生成,不引用任何第三方角色形象
- 主题感知 — 19 个主题覆盖 AI、技术、金融、知识、太空、音乐等领域,根据场景内容自动切换外观
- 视觉质量 — 手绘抖动路径、多层级细节、呼吸和入场动画,人物从"几乎不可见"提升到"主题特征清晰可辨"
打包与分发
效果确认后,我让 AI 把项目打包成可分发的 zip:
我:提供 Skills 下载的 zip 包
AI 排除了 node_modules、build 缓存和大体积视频文件,打包后的 zip 包含 Skill 定义文件(SKILL.md)、Python 管线脚本、Remotion 渲染引擎和所有 SVG 组件源码。
渲染配置也踩了几个坑。Remotion 报 “concurrency is set higher than the amount of CPU cores available”,需要把并发数从 3 降到 2。Chrome 路径不存在的问题通过安装 google-chrome-stable 的 deb 包解决。最终的渲染命令是:
npx remotion render AnimeVideo /workspace/kimi-k3-latest.mp4 --concurrency=2
回顾:和 AI 协作的体会
这次优化从提出需求到最终交付,整个过程都在 TRAE Work 里完成。我发了五条指令,AI 每条都理解到位并执行:
第一条"深度优化 Skills"——AI 分析了项目架构,设计了三模块解耦方案,实现了 1300 行 SVG 渲染引擎。
第二条"提供视频内容"——AI 渲染了视频,但结果有问题。
第三条"不对,这个版本不正确"——我纠正了方向,AI 修正了桥接层并重新渲染。
第四条"提供 zip 包"——AI 打包了项目。
第五条"整理成教程文章"——就是这篇文章本身。
整个过程里最有价值的不是 AI 一次写对了多少代码,而是它对需求的拆解能力。我说"根据文章主题内容来生成人物",AI 自己推导出了"需要内容分析引擎 + 主题映射表 + 模块化渲染函数"三层架构,这个设计比我自己想的都清楚。
当然也有不足。第一版渲染出来角色几乎不可见,说明 AI 对视觉效果的实际呈现缺乏预判——它知道代码逻辑是对的,但不知道 14.5% 的透明度在浅色背景上会是什么效果。这种"代码正确但效果不对"的情况,需要人类来验收和反馈。我在第三条指令里指出的问题,本质上就是在做这一层质量控制。
如果要做类似的项目,我的建议是:把需求说清楚(弃用 PNG、SVG 生成、主题感知),让 AI 设计架构和写代码,但每一版都要自己看实际渲染效果,用具体的反馈推动优化。AI 写代码快,但"看起来对不对"这件事,目前还是人说了算。








