跳到主要内容

快速开始

在本指南中,我们将使用 Motion Canvas 创建一个简单的动画。

前置条件

确保您的机器上安装了 Node.js 版本 16 或更高版本。

您可以运行以下命令来检查是否已安装 Node.js:

node -v

创建新项目

运行以下命令以脚手架一个新的 Motion Canvas 项目(如果命令失败,请查看下面的故障排除部分):

npm init @motion-canvas@latest

回答提示以命名您的项目并选择您想使用的语言;TypeScript 或纯 JavaScript。我们建议在您的第一个项目中使用 TypeScript,因为这是我们在整个文档中使用的语言。

您还将被要求选择如何导出您的动画。Motion Canvas 附带内置的图像序列导出器 - 如果您想将动画导入视频编辑器,这非常完美。但是,如果您想直接生成完成的视频,可以选择安装视频 (FFmpeg)导出器。别担心,您可以选择多个导出器,并且您可以随时稍后添加更多

要完成脚手架过程,您需要运行以下命令:

  1. Change Directory (cd)到项目根目录(您应该将 <project-path> 替换为在脚手架期间选择的路径):
    cd <project-path>
  2. 安装必要的依赖项:
    npm install
  3. 启动编辑器:
    npm start
    您可以通过访问 http://localhost:9000/ 来访问编辑器。我们将使用它来预览我们的动画,尽管目前没有太多可看的。

编程动画

脚手架命令将为您创建多个文件,但目前我们将专注于 src/scenes/example.tsx,这是我们可以添加动画的地方。在文本编辑器中打开 example.tsx,并将文件中的所有代码替换为以下代码片段。

Click to preview animation

import {makeScene2D, Circle} from '@motion-canvas/2d';
import {all, createRef} from '@motion-canvas/core';

export default makeScene2D(function* (view) {
const myCircle = createRef<Circle>();

view.add(
<Circle
ref={myCircle}
// 尝试更改这些属性:
x={-300}
width={140}
height={140}
fill="#e13238"
/>,
);

yield* all(
myCircle().position.x(300, 1).to(-300, 1),
myCircle().fill('#e6a700', 1).to('#e13238', 1),
);
});

现在保存文件。您所做的任何更改都会自动被拾取并在预览中反映出来。

您应该会在 Web 应用程序右上角的预览窗格中看到一个红色圆圈。按播放按钮查看圆圈在屏幕上动画。

说明

Motion Canvas 中的每个视频都由项目配置对象表示。在我们的示例中,此配置在 src/project.ts 中声明:

src/project.ts
import {makeProject} from '@motion-canvas/core';

import example from './scenes/example?scene';

export default makeProject({
scenes: [example],
});

创建项目时,我们需要为其提供要显示的场景数组。在这种情况下,我们只使用从 src/scenes/example.tsx?scene 导入的一个场景。

注意末尾的 ?scene - 这是将导入的模块转换为正确场景所必需的。除其他事项外,它使得在您修改场景时可以动态刷新预览。没有它,编辑器将无法工作。

场景是显示在屏幕上的一组元素和控制它们的动画。最基本的场景如下所示:

import {makeScene2D} from '@motion-canvas/2d';

export default makeScene2D(function* (view) {
// 动画
});

makeScene2D() 接受一个生成器函数并将其转换为一个场景,然后我们在我们的项目文件中导入它。生成器函数描述动画的流程,而提供的 view 参数用于向场景添加元素。

您可以在场景层次结构部分了解有关场景、节点和这种类似 XML 的语法的更多信息。目前,重要的是,在我们的示例中,我们向场景添加了一个单独的<Circle/>节点。我们将其设置为红色,将其宽度和高度设置为 140 像素,并将其定位在中心左侧 300 像素处:

view.add(
<Circle
ref={myCircle}
x={-300}
width={140}
height={140}
fill="#e13238"
/>,
);

要为我们的圆圈设置动画,我们首先需要获取对它的引用。这就是createRef函数的目的。我们使用它创建一个引用,并使用ref属性将其传递给我们的圆圈:

const myCircle = createRef<Circle>();

view.add(
<Circle
ref={myCircle}
x={-300}
width={140}
height={140}
fill="#e13238"
/>,
);

然后我们通过 myCircle() 访问圆圈并为其属性设置动画:

yield *
all(
myCircle().fill('#e6a700', 1).to('#e13238', 1),
myCircle().position.x(300, 1).to(-300, 1),
);

此代码片段可能看起来有点令人困惑,所以让我们分解一下。

节点的每个属性都可以在整个动画过程中读取和更新。例如,在上面的圆圈中,我们将它的 fill 属性定义为 '#e13238':

<Circle
ref={myCircle}
x={-300}
width={140}
height={140}
fill="#e13238"
/>

使用我们的引用,我们现在可以检索此属性的值:

const fill = myCircle().fill(); // '#e13238'

我们还可以通过将新值作为第一个参数来更新它:

myCircle().fill('#e6a700');

这将立即更新我们圆圈的颜色。如果我们想在一段时间内过渡到新值,我们可以将过渡持续时间(以秒为单位)作为第二个参数传递:

myCircle().fill('#e6a700', 1);

这会创建一个补间动画,在一秒钟内平滑地更改填充颜色。

Motion Canvas 中的动画不会自行播放,我们需要明确告诉它们播放。这就是为什么使用生成器函数声明场景 - 它们作为动画应该如何播放的描述。通过 yield 不同的指令,我们可以告诉场景动画做不同的事情。

例如,要播放我们创建的补间,我们可以这样做:

yield * myCircle().fill('#e6a700', 1);

这将暂停生成器,播放我们 yield 的动画,然后继续。

要在第一个动画之后立即播放另一个动画,我们可以简单地编写另一个 yield* 语句:

yield * myCircle().fill('#e6a700', 1);
yield * myCircle().fill('#e13238', 1);

但由于我们正在为同一个属性设置动画,我们可以用更紧凑的方式编写它:

yield * myCircle().fill('#e6a700', 1).to('#e13238', 1);

在我们的示例中,除了更改颜色外,我们还移动了圆圈。我们可以尝试按照为颜色设置动画的相同方式进行操作:

yield * myCircle().fill('#e6a700', 1).to('#e13238', 1);
yield * myCircle().position.x(300, 1).to(-300, 1);

这可行,但是位置将在填充颜色之后开始动画。要使它们同时发生,我们使用 all 函数:

yield *
all(
myCircle().fill('#e6a700', 1).to('#e13238', 1),
myCircle().position.x(300, 1).to(-300, 1),
);

all 接受一个或多个动画并将它们合并在一起。现在它们将同时发生。动画流程部分更深入地介绍了生成器和流程函数,如 all

这让我们回到最初的示例:

src/scenes/example.tsx
import {Circle, makeScene2D} from '@wangyaoshen/locus-2d';
import {all, createRef} from '@wangyaoshen/locus-core';

export default makeScene2D(function* (view) {
const myCircle = createRef<Circle>();

view.add(
<Circle
ref={myCircle}
x={-300}
width={140}
height={140}
fill="#e13238"
/>,
);

yield* all(
myCircle().position.x(300, 1).to(-300, 1),
myCircle().fill('#e6a700', 1).to('#e13238', 1),
);
});

故障排除

Details

npm init @motion-canvas@latest 执行失败。

npm 中有一个错误导致上述命令失败。它在版本 8.15.1 中得到了修复。您可以按照此指南来更新您的 npm。或者,您可以改为使用以下命令:

npm exec @motion-canvas/create@latest
Details

npm install 失败,错误为 code ENOENT

如果 npm install 失败并出现以下错误:

npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path [path]\package.json
npm ERR! errno -4058
npm ERR! enoent ENOENT: no such file or directory, open '[path]\package.json'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

确保您在正确的目录中执行命令。当您使用 npm init 完成项目的引导时,它将显示三个命令:

cd [path]
npm install
npm start

您是否运行了 cd 命令来切换到包含您的项目的目录?

Details

我将摄像机移动得太远,无法找到预览(预览为黑色)

您可以按 0 重新聚焦摄像机上的预览。

Details

动画突然结束或不是从头开始。

确保时间轴中的播放范围选择器在您期望的位置开始和结束,例如,在动画的开始和结束处。范围选择器是时间轴时间轴上的灰色条。当您将鼠标移到它上面时,会出现六个点,允许您操作它。

Details

文件监视在适用于 Linux 的 Windows 子系统 (WSL) 2 上不起作用

在 WSL2 上运行 Vite 时,如果文件由 Windows 应用程序编辑,则文件系统监视不起作用。

要解决此问题,请将项目文件夹移动到 WSL2 文件系统,并使用 WSL2 应用程序编辑文件。从 WSL2 访问 Windows 文件系统很慢,因此这将提高性能。

有关更多信息,请查看Vite 文档