本文件为 Claude Code (claude.ai/code) 在本仓库中工作时提供指引。
文本转视频生成流水线。接收描述视频结构(封面、场景、结束语)的 JSON 输入,输出带 TTS 旁白、字幕和模板视觉样式的 MP4 视频。
pnpm build # 构建所有包 (turbo)
pnpm typecheck # 类型检查所有包
pnpm lint # Lint 所有包
# 运行视频渲染
node apps/cli/dist/index.js render test/fixtures/sample-knowledge.json -t knowledge -p bilibili
# Web UI 开发服务器
cd apps/web && pnpm dev
pnpm workspaces + Turborepo 的 monorepo 结构。
apps/cli/ CLI 入口 (Commander)
apps/web/ Next.js 15 WebUI + API 路由
packages/shared/ Zod schema、类型定义、常量、LLM 客户端
packages/core/ 流水线编排与 6 个阶段
packages/tts/ TTS provider 注册表 + 4 个 provider
packages/templates/ 5 个模板的 Remotion React 组件
输入始终是结构化 JSON (VideoInputSchema)。流水线在 packages/core/src/stages/ 中依次执行 6 个阶段:
VideoInputSchema 验证 JSON,转换为内部 ParsedContent(cover → scene-0,outro → 最后一个 scene)。github-trending 模板的 cover 场景在这里确定性写入开场口播(masthead + "今日精选 N 个项目"),并承载 LLM 产出的 coverTags(≤5 个主题标签)与 trendSummary(一句话趋势总结),由模板在首屏渲染;不再注入单独的 summary 场景path > 远程 url > 关键词 query),复制背景图/字体ComposedProject,word timestamps 转为场景内相对时间。逐字段拷贝场景数据——新增场景字段时必须在此阶段显式透传(buildInputProps 用 ...scene 自动透传,但 compose 是手写字段映射)renderMedia 渲染核心类型链:VideoInput → ParsedContent → ComposedProject → Remotion props。
Remotion 通过其 webpack dev server 提供所有静态资源。组件中绝不能使用文件系统绝对路径 — 必须使用 staticFile(filename)。render 阶段会将所有资源(音频、图片、背景图)复制到统一的 publicDir,通过 props 传递文件名。
音频按场景独立播放:每个 <Sequence> 包含自己的 <Audio> 组件,不使用全局音频轨道。
Provider 通过 registerProvider() 在 packages/tts/src/providers/ 中注册。每个 provider 实现 TTSProvider 接口(synthesize、listVoices、align)。新增 provider 的方式:在 providers/ 下创建文件并在 index.ts 中 import。
5 个模板(news、knowledge、opinion、marketing、github-trending),每个在 packages/templates/src/<name>/index.tsx 中有对应的场景组件。共享基础组件位于 packages/templates/src/base/。Root.tsx 按以下规则路由:
sceneType === "cover" → 内置 CoverScene(github-trending 的 cover 接收 coverTags/trendSummary,在首屏渲染主题标签行 + 一句话趋势句)sceneType === "outro" → 内置 OutroSceneSCENE_MAP[template] 对应模板组件github-trending 是当前唯一带 isPortrait 分支的模板,竖屏布局采用 flex column(头部取自然高度,内容 flex 填充),横屏保持绝对定位。Section 子组件通过 size: "default" | "large" 区分横竖屏字号档位,并用 -webkit-line-clamp 做安全截断(body 用 flex: "0 0 auto" 防止 shrink 导致的单行底部裁剪)。
SubtitleBar(packages/templates/src/base/components/subtitle-bar.tsx)接受可选 fontSize 和 style prop——竖屏场景可传 { bottom: 380 } 提高字幕位置、fontSize: 56 放大字号;横屏不传则保持默认(bottom: 60、fontSize: 40)。
.env(monorepo 根目录)— 所有 provider 的 API Key(CLI 启动时加载,Next.js 通过 next.config.ts 加载)config/default.yaml — TTS provider、模型、模板配色、输出设置--config 参数 → pipeline.config.yaml → config/default.yaml全部在 packages/shared/src/types/ 中用 Zod 定义:
VideoInputSchema — 用户输入格式(title、subtitle、cover、scenes[]、outro、globalStyle;github-trending 另有可选 coverTags/trendSummary,由 LLM 产出)SceneSchema — 内部场景,含 sceneType: "cover" | "content" | "summary" | "outro"、可选 github(GithubSceneData)、可选 coverTags(string[])/trendSummary(string,仅 github-trending 的 cover 场景使用)ComposedSceneSchema — compose 后的场景,含帧时间轴、audioPath、已解析的图片。字段与 SceneSchema 一一对应PipelineInputSchema — 顶层流水线输入(text、template、platform、ttsProvider)新增场景字段时三个 schema 都要同步: SceneSchema(scene.ts)、ComposedSceneSchema(pipeline.ts)、RemotionScene(Root.tsx 的 interface)。还要在 compose.ts 手动透传(不是 ...scene 展开),否则字段会在 compose 阶段丢失。
LLMClient(packages/shared/src/llm/client.ts)显式设置 max_tokens: 8192——github-trending 多仓库结构化 JSON 输出约 6000 tokens,provider 默认值(1024-4096)会截断响应导致 JSON 解析失败github-trending 的 cover narration 是 parse.ts 硬编码模板字符串(含日期和仓库计数),不交给 LLM;但首屏的 coverTags(≤5 个主题标签)与 trendSummary(一句话趋势)由 LLM 产出并透传到 cover 场景渲染。LLM 仍只产出 per-repo scenes[],不生成 overview/summary 场景--no-tts 跳过(生成静音视频)