┌──────────┐ /api ┌──────────┐ spawn ┌──────────────┐
│ web │ ────────▶ │ server │ ──────▶ │ render │
│ React 19 │ │ Fastify │ │ Remotion CLI │
│ :3000 │ ◀──────── │ :4000 │ ◀────── │ 无头 Chromium│
└──────────┘ SSE └──────────┘ mp4 └──────────────┘
web通过/api相对路径访问后端,开发和生产都不需要改地址server用spawn调起render工程的 Remotion CLI,渲染是独立进程,不阻塞 API- 桌面版下
web的构建产物由server一并托管,两者合并成一个进程组
├─ shared/ # 前后端共享类型契约
├─ desktop/ # 桌面版外壳(Electron)
│ ├─ src/
│ │ ├─ main.ts # 主进程:拉起后端 / 窗口 / 菜单 / 设置 IPC
│ │ ├─ server.ts # 后端子进程管理与健康探测
│ │ ├─ preload.ts # contextBridge 暴露的设置 API
│ │ ├─ paths.ts # 资源路径与免安装模式
│ │ ├─ config.ts # 配置读写(userData/config.json)
│ │ └─ browser.ts # Chromium / ffmpeg 探测
│ ├─ scripts/
│ │ ├─ make-icon.mjs # 从 web 的 svg 生成三平台图标
│ │ ├─ copy-ffmpeg.mjs # 内置 ffmpeg 到 build/bin
│ │ ├─ stage-server.mjs # 暂存后端(重装依赖 + 过滤产物)
│ │ └─ verify-pack.mjs # 打包产物自检
│ ├─ assets/settings.html # 设置面板
│ ├─ portable.txt # 免安装模式标记(随包发布)
│ └─ electron-builder.yml
├─ web/ # 前端(React + Vite)
│ └─ src/
│ ├─ App.tsx # 四步流程壳 + 步骤条
│ ├─ api.ts # /api 客户端 + SSE 订阅
│ └─ components/ # 输入 / 大纲 / 分镜 / 缩略图 / 渲染 / 页编辑器
└─ server/
├─ src/
│ ├─ index.ts # Fastify 入口(:4000)
│ ├─ routes/ # generate / stream / tasks / media / health / static
│ └─ services/
│ ├─ storyboardGenerator.ts # 大纲 + 多 pass 分镜管线
│ ├─ prompts.ts / normalize.ts # prompt 模板 / JSON 归一化与告警
│ ├─ renderService.ts / entry.ts # 渲染编排 / Remotion 入口生成
│ ├─ frameExtract.ts # 预览帧导出(ffmpeg 优先,remotion still 回退)
│ ├─ ttsService.ts / bgmService.ts
│ ├─ fetchUrl.ts / llmClient.ts # 网页抓取 / LLM 流式客户端
│ ├─ runtime.ts # 路径与对外基址收口(支持桌面版重定向)
│ ├─ deps.ts # 渲染依赖校验 / WAV 时长解析
│ └─ taskStore / sseHub / renderQueue / auth / env
├─ render/ # Remotion 渲染工程
│ └─ src/
│ ├─ DynamicVideo.tsx # 主组件(TransitionSeries + 转场 + 频谱 + 版式分发)
│ ├─ shared/render/
│ │ ├─ scenes/ # 16 个场景组件
│ │ └─ theme.ts props.ts Card.tsx Icon.tsx Bg.tsx ...
│ └─ gen/ # 运行时生成的入口(每次渲染覆盖,不入库)
└─ out/ assets/ tts/ # 运行时产物:成片 mp4、预览帧 PNG、TTS / BGM wav
server/src/services/runtime.ts是关键:它把散落各处的路径与对外基址统一收口, 桌面版通过TTT_*环境变量重定向到 userData,业务代码无需感知运行环境。
| 层 | 技术 |
|---|---|
| 前端 | React 19 · Vite 8 · TypeScript |
| 后端 | Node.js · Fastify 5 · TypeScript(tsx watch 热载) |
| 桌面 | Electron 44 · electron-builder |
| 渲染 | Remotion 4.0(无头 Chromium)· transitions · rough-notation · paths · shapes · media-utils |
| 网页抓取 | Node 内置 fetch(轻量)+ Playwright(JS 动态页兜底) |
| TTS | msedge-tts(Edge 在线音色)+ ffmpeg 转码 |
| BGM | 自研纯 Node 合成(44.1kHz 手写 WAV,无任何音频素材) |
| LLM | OpenAI 兼容接口(/chat/completions 流式) |
后端 storyboardGenerator 采用「大纲 → 分镜」两段式 LLM 流水线,中间夹一层强类型归一化:
| 阶段 | 作用 |
|---|---|
| Pass 1 · 大纲规划 | 定全局 arc 叙事弧线与每页 role / icon / layout / art / chart / table / rhythm,流式流出供确认与编辑 |
| Pass 2 · 逐页展开 | 基于确认后的大纲逐页填充标题 / 要点 / 解说 / 字幕,注入上一页上下文保持连贯(SSE 实时流出) |
| normalize | LLM JSON → 强类型分镜;越界值收敛、缺失字段补全,并产出「某页与大纲版式偏差 / 图表未兑现 / 要点过多」等偏差告警 |
| fallbackDirect | 管线异常时直出兜底分镜,保证不中断 |
逐句 TTS ──▶ 按整片时长合成 BGM ──▶ 生成自包含 Remotion 入口 ──▶ 无头 Chromium 逐帧导出带声 MP4
(3 并发 + (纯 Node 数学生成 (写入 render/src/gen/) (并发数由 RENDER_CONCURRENCY 控制)
3 次退避重试) 琶音+低音+包络)
渲染前会先跑一次依赖校验(services/deps.ts):
- 缺 ffmpeg → 直接失败并给出准确原因(否则会一路跑到 TTS 全部失败, 报出误导性的「TTS 合成失败」)
- 缺 Chromium → 提示指定浏览器路径;若只是未探测到,则挂一条 warning, Remotion 会尝试联网下载自带内核