返回博客

我如何用 React 构建了一个视频渲染系统

·1 分钟阅读

视频的问题

我需要为三个品牌制作宣传视频。ShawnOS、GTMOS、ContentOS。每个都需要三种宽高比 - LinkedIn (4:5)、Reels (9:16)、横屏 (16:9)。这就是九个渲染目标。而且每次设计令牌变化,每个视频都需要更新。

我看了 After Effects 模板。看了 Canva。考虑过找人做。每个选项都意味着一个手动管道,在我推送一次颜色变更后就会与网站不同步。

网站已经有了设计系统。数据层。品牌令牌。如果视频也在同一个代码库里呢?

Remotion 和单仓库优势

Remotion 把 React 组件变成视频帧。你写 JSX。它以 30fps 渲染每一帧。你得到一个 MP4。不需要 GPU。不需要时间线编辑器。只要代码。

关键洞察是把视频应用放进现有的 Turborepo 单仓库,在 website/apps/video/。同一个驱动三个网站的 @shawnos/shared 包。同样的设计令牌。同样的调色板。当我修改共享包里的一个十六进制值时,网站和视频在下次构建时都会更新。

九个合成存在于一个 Root.tsx 中。三个品牌乘以三种宽高比。一个 useScale() 钩子将一切标准化到 1080x1350 基准并按比例缩放。一棵组件树可以以任何尺寸渲染。

场景架构

视频由通过 TransitionSeries 连接的场景构建 - Remotion 的合成工具,处理片段之间的重叠时序。每个场景是一个有固定帧数的 React 组件。

当前 V3 系统运行约10秒,30fps(共310帧):

  • Hook(36帧 / 1.2秒) - 开场抓眼球
  • BootWikiBlitz(110帧 / 3.7秒) - 终端启动序列配合快速切换的 Wiki 卡片
  • Progression(100帧 / 3.3秒) - RPG 风格等级系统可视化
  • CtaNetwork(94帧 / 3.1秒) - 带网络图的行动号召

场景之间有10帧的转场重叠。时序配置在 timing-v2.ts 中 - 一个文件控制整个视频节奏。

组件库

三个组件完成了大部分视觉工作。

MatrixRain 使用来自 @remotion/noise 的 Perlin 噪声生成确定性的字符雨效果。每一列独立漂移。字符选择由列、行和帧号作为种子。效果是有机的但可复现的 - 同一个种子,同一个输出,每次渲染。

TypewriterText 逐帧显示字符,带闪烁光标。已过帧数控制可见字符数。光标以 1Hz 闪烁。简单的数学,干净的效果。

ParticleField 使用两个独立的噪声流创建环境浮动粒子,分别用于 x 和 y 漂移。默认40个粒子,限制在画布8%的漂移范围内。通过第三个噪声通道实现微妙的脉冲效果。

三个组件都是确定性的。没有 Math.random()。Remotion 要求如此 - 随机值在帧之间变化会破坏渲染。带一致种子的 Perlin 噪声给你有机动画,同时保持可复现性。

视觉处理

每个场景都包裹在 SceneWrapper 中,应用一致的视觉处理:

  • 深色画布背景 (#0D1117)
  • 径向暗角(边缘加深)
  • 3%透明度的主题色染色
  • 粒子场环境噪声
  • 通过 SVG feTurbulence 实现的胶片颗粒
  • 扫描线叠加(CRT 美学)

结果看起来像终端原生视频。符合 ShawnOS 品牌,不需要任何手动后期处理。

代码中的设计令牌

令牌系统在 tokens.ts 中:

canvas:  #0D1117
green:   #4EC373  (ShawnOS)
teal:    #3DBFA0  (GTMOS)
purple:  #9B72CF  (ContentOS)
amber:   #D2A53C  (辅助色)

SITE_ACCENTS 将品牌名映射到颜色。BootWikiBlitz 场景在 Wiki 卡片翻转时循环调色板 - 绿色、青色、琥珀色、紫色、绿色。品牌标识在数据中,不是硬编码在组件里。

字体统一使用 JetBrains Mono。等宽字体。与三个网站的终端美学一致。

渲染

npm run render:all 生成全部九个变体。Remotion 将每个合成渲染为 JPEG 帧,然后编码为 MP4。除了 package.json 中的依赖外没有外部依赖。不需要云端渲染农场。在 MacBook 上运行。

渲染输出到 website/apps/video/out/,部署到每个网站的 public/video/ 目录。SQLite 内容索引追踪所有视频文件、它们的品牌、宽高比和部署状态。

为什么这很重要

视频系统是与所有其他内容类型共存于同一代码库的一种内容类型。博客文章是 markdown 文件。知识术语是 TypeScript 对象。视频是 React 组件。它们都共享相同的设计令牌、相同的数据层、相同的部署管道。

当我添加新的 Wiki 类别时,BootWikiBlitz 场景可以引用它。当我改变品牌颜色时,视频会更新。当我推送到 main 时,一切一起部署。

没有独立工具。没有手动导出。没有同步问题。单仓库就是系统。

$ remotion render Root LeadMagnetV3 --codec=h264

ShawnOS.ai|theGTMOS.ai|theContentOS.ai
built with Next.js · Tailwind · Claude · Remotion