学习Remotion用HTML、CSS和React创建动画视频

1,375 阅读10分钟

Remotion: Create Animated Videos Using HTML, CSS and React

用文字、动画、颜色和形状创建一个视频,传统上需要专业软件和可能多年的动态图形培训。如果你可以使用你现有的工具集、培训和网络开发背景来做同样的事情,会怎么样?

Remotion允许JavaScript开发人员重新使用他们已经建立的技能和知识,使用HTML、CSS和React JS创建复杂的动画视频。如果你能用React渲染文本,为CSS样式制作动画,或组织HTML内容,现在你就可以只用代码来创建和编辑自己的视频,而不需要视频编辑应用程序或软件。

在这篇文章中,我将介绍使用Remotion的过程,并在过程中向你讲述我的发现。

你可以在GitHub上找到这篇文章的完整代码。

Remotion:什么,以及为什么?

Remotion是一个由Jonny Burger创建的React的视频创作工具包。这个工具包允许任何对React、HTML或CSS有基本了解的人使用代码来创建动画视频。

在视频创作领域,由于使用和掌握这些工具所需的软件和培训,目前有很高的准入门槛。通过利用JavaScript开发人员现有的工具包,这为更多的用户打开了视频创作空间。随着视频变成代码,我们可以利用现有的模式来实现更有效的视频创作--比如基于参数或构建管道的自动生成。

开始使用

值得庆幸的是,Remotion有一个快速而简单的设置过程,有一个Yarn和npm的入门套件。在这个例子中,我们将坚持使用npm作为构建和运行工具。在我们开始之前,你需要安装好Node和npm。(如果需要帮助,你可以按照这个指南来安装Node和npm。)如果你在Linux上,也可以查看Remotion安装指南,因为你可能需要安装额外的工具。在设置好Node和npm之后,让我们通过运行这段代码创建一个新的项目。

npm init video

这将提示你一个项目名称,它也被用作目录名称。在我们的例子中,它将是my-video 。输入后,我们可以进入my-video 目录,并通过运行如下的启动脚本来启动默认的视频项目。

cd my-video
npm start

运行start命令后,浏览器应该自动打开。如果没有,请打开浏览器并导航到http://localhost:3000/。这个功能允许你观看和调试你正在创建的视频。该播放器的控件包括一个播放按钮,可以让你预览视频内容。从看演示例子的代码开始可能也是有用的,Remotion提供了一个如何建立你自己的视频的指南。

你好,世界!

我们将创建我们自己的视频,以 "Hello, World!"为主题,来了解Remotion中提供的组件和流程。

首先,让我们删除现有的示例代码(src 文件夹中的所有内容),因为我们想重新开始。然后,让我们在src 目录下创建一个Demo 目录,它将保存和管理这个项目的所有视频工作。在Demo 目录下,创建一个Demo.js 文件。

import {Composition, interpolate, Sequence, useCurrentFrame, useVideoConfig} from 'remotion';
import Title from './Title';
import Hello from './Hello';
import "./demo.css";

const Demo = () => {
  return (
  <div className="main-container">
    {/* TODO: add video content */}
  </div>
  );
};

export const DemoVideo = () => {
  return (
  <Composition
    id="Demo"
    component={Demo}
    durationInFrames={150}
    fps={30}
    width={1920}
    height={1080}
    defaultProps={{
      titleText: 'This is my first Remotion video',
      titleColor: 'blue',
    }}
    />
  )
}

Demo 文件导出我们的视频代码。正如你所看到的,我们可以创建一个Demo 组件,它将容纳我们视频中的所有视觉元素。然后我们可以导出一个组件,渲染我们视频的CompositionComposition 组件允许我们定义一些基本属性,如视频片段的宽度和高度,FPS(每秒帧数),以及将被渲染的特征。我们还从Remotion导入了一些工具和钩子,以及一些我们即将创建的额外组件。

目前我们的Demo 组件是空的,但让我们为我们的视频添加一些元素。

const Demo = ({titleText, titleColor}) => {
  const frame = useCurrentFrame();
  const videoConfig = useVideoConfig();

  const totalOpacity = interpolate(
     frame,
     [videoConfig.durationInFrames - 25, videoConfig.durationInFrames - 15],
     [1, 0],
    {
      extrapolateLeft: 'clamp',
      extrapolateRight: 'clamp',
    }
  );

  return (
    <div className="main-container">
      <div style={{opacity: totalOpacity}}>
        <Sequence from={0} durationInFrames={videoConfig.durationInFrames / 2}>
          <Hello/>
        </Sequence>
        <Sequence from={35} durationInFrames={Infinity}>
          <Title titleText={titleText} titleColor={titleColor} />
        </Sequence>
      </div>
    </div>
  );
};

我们在文件中添加了很多东西,所以让我们把这些都分解开来。

首先在我们的渲染部分,我们可以从文件中看到,我们现在可以返回一个带有不透明度样式的div,允许我们在视频的开始和结束时淡入和淡出元素。对于不透明度的值,我们使用了一个Remotion帮助器。interpolate 函数允许你更好地定义动画,并将动画值映射到当前帧和视频持续时间。在这个例子中,我们传入当前帧。该函数将在每一帧生成时被调用。输入范围是根据视频的持续时间计算的,输出值的范围是0到1,因为这是不透明度CSS值的范围。由于Demo ,每一帧都要重新渲染,interpolate 函数每次都被调用,并将返回适当的不透明度值。

接下来,我们可以开始在视频屏幕上渲染不同的视觉元素。在这个例子中,我们希望文本 "Hello, World!"淡入视野然后消失,随后出现文本 "This is my first Remotion video"。要做到这一点,我们可以渲染多个Sequence 组件。

Sequence 组件是另一个Remotion功能,它允许我们定义一个组件在视频中的渲染方式和时间,以及渲染的时间。这对于构建复杂的视频,你想添加定时或分层的元素是非常好的,比如这个例子。每个Sequence ,也会显示在浏览器的播放器中,并根据子组件的名称来命名。这让你可以实时监控你正在生成的视频和你正在添加的效果。

Remotion还提供了一些有用的React钩子,在这个例子中,我们使用了useCurrentFrameuseVideoConfig 钩子。useCurrentFrame 将返回视频当前所在的帧,这对于动画和基于视频播放的当前位置实现动作很有用。useVideoConfig 将返回一个具有不同值的对象,例如。

  • width: 视频的宽度 - 对视频中的元素定位很有用
  • height:视频的高度--对定位视频中的元素很有用
  • FPS:每秒的帧数--可用于确定动画或元素的移动速度
  • durationInFrames:视频的总长度,以帧为单位--可用于计算动画或Sequence 显示和隐藏的时间。

在我们的案例中,如前所述,首先我们希望我们的Hello 组件,文本 "Hello, World!",在视频开始时出现,并在屏幕上保持一半的时间。我们通过使用videoConfig.duration ,这个值是我们从useVideoConfigHook 计算出来的。

对于第二个Sequence ,我们希望我们的Title 组件文本 "这是我的第一个Remotion视频 "在35帧后出现,并在视频的整个过程中保持在屏幕上。为了达到这个目的,我们为From ,输入35 ,为durationInFrames ,输入Infinity

为了给我们的演示组件设置样式,我们可以使用CSS和内联样式。当使用CSS时,我们希望将样式应用于整个视频,所以让我们创建一个demo.css ,该文件将容纳覆盖整个视频区域的任何样式。在我们的例子中,我们想让背景变成白色,并使用Flexbox对齐项目。

.main-container {
    flex: 1;
    background-color: white;
}

现在让我们更深入地了解我们正在渲染的这些元素。

渲染动画中的React组件

Hello 组件将是一个基本的 React 组件,它渲染了一个 H1 标签,并应用了一些内联样式和文本 "Hello, World!"这是我们可以渲染的最简单的组件形式。为了简单起见,我们可以使用内联样式。但因为这是React,你也可以从CSS文件中导入样式,使用类名、styled-components、CSS模块或任何你已经熟悉的样式模式作为替代。让我们来创建Hello 组件。在Demo 文件夹内,创建一个新文件Hello.js

const Hello = () => {
  return (
    <h1
      style={{
        fontFamily: 'SF Pro Text, Helvetica, Arial',
        fontWeight: 'bold',
        fontSize: 100,
        textAlign: 'center',
        position: 'absolute',
        bottom: 500,
        width: '100%'
      }}
    >
      Hello, World!
    </h1>
  );
};

export default Hello;

现在,让我们来看看一个更复杂的例子。在Demo 文件夹中,创建一个名为Title.js 的新文件,并加入下面的组件代码。

import {spring, useCurrentFrame, useVideoConfig} from 'remotion';

const Title = ({titleText, titleColor, bottom}) => {
  const videoConfig = useVideoConfig();
  const frame = useCurrentFrame();
  const text = titleText.split(' ').map((t) => ` ${t} `);
  return (
    <h1
      style={{
        fontFamily: 'SF Pro Text, Helvetica, Arial',
        fontWeight: 'bold',
        fontSize: 100,
        textAlign: 'center',
        position: 'absolute',
        bottom: bottom || 160,
        width: '100%',
      }}
    >
      {text.map((t, i) => {
        return (
          <span
            key={t}
            style={{
              color: titleColor,
              marginLeft: 10,
              marginRight: 10,
              transform: `scale(${spring({
                fps: videoConfig.fps,
                frame: frame - i * 5,
                config: {
                  damping: 100,
                  stiffness: 200,
                  mass: 0.5,
                },
              })})`,
              display: 'inline-block',
            }}
          >
            {t}
          </span>
        );
      })}
    </h1>
  );
};

export default Title;

我们在这里有很多事情要做,所以再次让我们分解一下正在发生的事情。

Remotion对TypeScript有一流的支持。这不是必须的,但它可以使开发过程变得更好,因为你会在IDE中得到更详细的自动完成建议。然而,为了使这个例子对初学者更友好,我们将只使用普通的JavaScript。

我们的组件接收了两个道具--titleTexttitleColor --这些道具将在后面的渲染方法中使用。这表明,使用React,我们仍然可以在应用程序中传递道具,因此使我们的视频元素可重复使用和动态。你可能已经注意到,在我们的Demo 组件中,我们从Composition 组件中传入道具。这显示了React在行动上的力量。我们可以从React应用程序的顶部传递道具,使视频具有响应性,这意味着你可以改变一个文本块来制作一个新的视频或改变整个视频的上下文。

在我们访问了Title 组件中的道具后,我们再次调用Remotion钩子以获得videoConfig 和帧数据。然后,Title 组件打破了传递的文本道具,并使用地图和CSS变换的组合,一个字一个字地渲染它。在这里,我们有机会使用另一个内置的辅助函数。Spring 收取数值,以帮助为动画值生成一个平滑输出。我们传递主视频配置的FPS来控制动画的速度。帧值控制动画开始的时间,最后我们传入额外的配置选项来控制动画的平滑度。

在我们创建了所有的视频组件并准备就绪后,我们需要最后在src 文件夹的根部创建一个index.js 文件并添加以下内容。

import {registerRoot} from 'remotion';
import { DemoVideo } from './Demo/Demo';

registerRoot(DemoVideo);

该索引文件从Remotion中导入了registerRoot 函数,它允许我们渲染视频内容。可以把它看作是ReactDOM的渲染函数,但是对于Remotion来说。然后我们将我们的DemoVideo 组件传递给registerRoot ,它将在开发或构建模式下将渲染的视频可视化。

我们现在正在导入Demo视频,它将被Remotion渲染。

现在,我们有了所有这些功能的组合,我们有了一个完整的动画视频,它提供了一个由Remotion提供的不同组件和辅助函数的例子。

我们可以用下面的命令从项目的根目录下运行这个视频。

./node_modules/.bin/remotion preview src/index.js

或者,你可以更新package.json 文件中的start 脚本。

- "start": "remotion preview src/index.tsx",
+ "start": "remotion preview src/index.js",

然后用npm start 来运行该动画。

继续阅读Learn Remotion:用HTML、CSS和React创建动画视频onSitePoint.