重新创建苹果烟花动画
学习如何使用这个适合初学者的 Remotion 教程创建苹果在节假日网站上展示的动画!

视频版本
此教程也有视频版本可供参考:
源代码
入门指南
开始一个新的 Remotion 项目并选择空白模板:
- npm
- yarn
- pnpm
bash
npm init video --blank
bash
npm init video --blank
bash
pnpm create video --blank
bash
pnpm create video --blank
bash
yarn create video --blank
bash
yarn create video --blank
组合设置
<Composition>
定义视频的尺寸和持续时间。在 src/Root.tsx
文件中,将宽度和高度调整为以下内容:
src/Root.tsxtsx
export constRemotionRoot :React .FC = () => {return (<><Composition id ="MyComp"component ={MyComposition }durationInFrames ={150}fps ={30}width ={1920}height ={1080}/></>);};
src/Root.tsxtsx
export constRemotionRoot :React .FC = () => {return (<><Composition id ="MyComp"component ={MyComposition }durationInFrames ={150}fps ={30}width ={1920}height ={1080}/></>);};
创建背景
创建一个新文件 src/Background.tsx
并返回一个带有线性渐变的背景:
src/Background.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constBackground :React .FC = () => {return (<AbsoluteFill style ={{background : "linear-gradient(to bottom, #000021, #010024)",}}/>);};
src/Background.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constBackground :React .FC = () => {return (<AbsoluteFill style ={{background : "linear-gradient(to bottom, #000021, #010024)",}}/>);};
将创建的背景添加到 <MyComposition/>
组件中,该组件可以在文件 src/Composition.tsx
中找到。此文件将包含您在本教程中创建的所有组件。
src/Composition.tsxtsx
export constMyComposition :React .FC = () => {return (<AbsoluteFill ><Background /></AbsoluteFill >);};
src/Composition.tsxtsx
export constMyComposition :React .FC = () => {return (<AbsoluteFill ><Background /></AbsoluteFill >);};
这将产生以下效果:
html
<img src="/img/apple-wow-tutorial/Background.png"/>## 渲染一个点通过创建一个新文件 `src/Dot.tsx` 并返回一个居中的圆来渲染一个白色的点。```tsx twoslash title="src/Dot.tsx"import React from "react";import { AbsoluteFill } from "remotion";export const Dot: React.FC = () => {return (<AbsoluteFillstyle={{justifyContent: "center",alignItems: "center",}}><divstyle={{height: 14,width: 14,borderRadius: 14 / 2,backgroundColor: "#ccc",}}/></AbsoluteFill>);};
html
<img src="/img/apple-wow-tutorial/Background.png"/>## 渲染一个点通过创建一个新文件 `src/Dot.tsx` 并返回一个居中的圆来渲染一个白色的点。```tsx twoslash title="src/Dot.tsx"import React from "react";import { AbsoluteFill } from "remotion";export const Dot: React.FC = () => {return (<AbsoluteFillstyle={{justifyContent: "center",alignItems: "center",}}><divstyle={{height: 14,width: 14,borderRadius: 14 / 2,backgroundColor: "#ccc",}}/></AbsoluteFill>);};
在你的主合成 src/Composition.tsx
中添加 <Dot>
:
src/Composition.tsxtsx
export constMyComposition :React .FC = () => {return (<AbsoluteFill ><Background /><Dot /></AbsoluteFill >);};
src/Composition.tsxtsx
export constMyComposition :React .FC = () => {return (<AbsoluteFill ><Background /><Dot /></AbsoluteFill >);};
现在我们在背景上有一个白色的点:

为点添加动画
让我们对上面创建的白色点应用一些动画。我们在一个新文件 src/Shrinking.tsx
中创建另一个组件 <Shrinking>
,然后将该组件包裹在主合成 src/Composition.tsx
中。
src/Shrinking.tsxtsx
import React from "react";import { AbsoluteFill, interpolate, useCurrentFrame } from "remotion";export const Shrinking: React.FC<{children: React.ReactNode;}> = ({ children }) => {const frame = useCurrentFrame();return (<AbsoluteFillstyle={{scale: String(interpolate(frame, [60, 90], [1, 0], {extrapolateLeft: "clamp",extrapolateRight: "clamp",}),),}}>{children}</AbsoluteFill>);};
src/Shrinking.tsxtsx
import React from "react";import { AbsoluteFill, interpolate, useCurrentFrame } from "remotion";export const Shrinking: React.FC<{children: React.ReactNode;}> = ({ children }) => {const frame = useCurrentFrame();return (<AbsoluteFillstyle={{scale: String(interpolate(frame, [60, 90], [1, 0], {extrapolateLeft: "clamp",extrapolateRight: "clamp",}),),}}>{children}</AbsoluteFill>);};
在你的主合成 src/Composition.tsx
中添加 <Shrinking>
组件:
tsx
export constMyComposition :React .FC = () => {return (<AbsoluteFill ><Background /><Shrinking ><Dot /></Shrinking ></AbsoluteFill >);};
tsx
export constMyComposition :React .FC = () => {return (<AbsoluteFill ><Background /><Shrinking ><Dot /></Shrinking ></AbsoluteFill >);};
现在,你有一些动作可以展示了。通过在主合成中使用 <Shrinking>
,你已经创建了一个缩放效果:

移动点
接下来,创建一个名为 <Move>
的组件。该组件具有一个弹簧动画,默认情况下从零到一,并且在下面的代码片段中持续四秒钟(durationInFrames: 120
):
src/Move.tsxtsx
importReact from "react";import {AbsoluteFill ,interpolate ,spring ,useCurrentFrame ,useVideoConfig ,} from "remotion";export constMove :React .FC <{children :React .ReactNode ;}> = ({children }) => {const {fps } =useVideoConfig ();constframe =useCurrentFrame ();constdown =spring ({fps ,frame ,config : {damping : 200,},durationInFrames : 120,});consty =interpolate (down , [0, 1], [0, -400]);return (<AbsoluteFill style ={{translate : `0 ${y }px`,}}>{children }</AbsoluteFill >);};
src/Move.tsxtsx
importReact from "react";import {AbsoluteFill ,interpolate ,spring ,useCurrentFrame ,useVideoConfig ,} from "remotion";export constMove :React .FC <{children :React .ReactNode ;}> = ({children }) => {const {fps } =useVideoConfig ();constframe =useCurrentFrame ();constdown =spring ({fps ,frame ,config : {damping : 200,},durationInFrames : 120,});consty =interpolate (down , [0, 1], [0, -400]);return (<AbsoluteFill style ={{translate : `0 ${y }px`,}}>{children }</AbsoluteFill >);};
将 <Move>
组件添加到你的合成 src/Composition.tsx
中。通过将缩小的点包裹在 <Move>
组件中,你可以通过结合移动和缩小的效果获得一个不错的动画:
src/Composition.tsxtsx
export constMyComposition = () => {return (<AbsoluteFill ><Background /><Move ><Shrinking ><Dot /></Shrinking ></Move ></AbsoluteFill >);};
src/Composition.tsxtsx
export constMyComposition = () => {return (<AbsoluteFill ><Background /><Move ><Shrinking ><Dot /></Shrinking ></Move ></AbsoluteFill >);};
点就这样飞起来了:

复制移动的点
这里变得有点棘手,但以下步骤将使你的动画更加有趣。首先,将一个 delay
属性添加到 <Move>
组件中,然后更改 spring()
函数的 frame
参数。
src/Move.tsxtsx
importReact from "react";import {AbsoluteFill ,interpolate ,spring ,useCurrentFrame ,useVideoConfig ,} from "remotion";export constMove :React .FC <{children :React .ReactNode ;delay : number;}> = ({children ,delay }) => {const {fps } =useVideoConfig ();constframe =useCurrentFrame ();constdown =spring ({fps ,frame :frame -delay ,config : {damping : 200,},durationInFrames : 120,});consty =interpolate (down , [0, 1], [0, -400]);return (<AbsoluteFill style ={{translate : `0 ${y }px`,}}>{children }</AbsoluteFill >);};
src/Move.tsxtsx
importReact from "react";import {AbsoluteFill ,interpolate ,spring ,useCurrentFrame ,useVideoConfig ,} from "remotion";export constMove :React .FC <{children :React .ReactNode ;delay : number;}> = ({children ,delay }) => {const {fps } =useVideoConfig ();constframe =useCurrentFrame ();constdown =spring ({fps ,frame :frame -delay ,config : {damping : 200,},durationInFrames : 120,});consty =interpolate (down , [0, 1], [0, -400]);return (<AbsoluteFill style ={{translate : `0 ${y }px`,}}>{children }</AbsoluteFill >);};
现在,让我们创建一个<Trail>
组件。它接受一些React子元素并对它们进行复制。该组件会为每个后续的点添加延迟,以便它们不会同时开始。每个点都会应用一个比前一个点小的比例。
将之前创建的<Move>
组件放在<Trail>
组件中。
这里的顺序至关重要。操作是从内到外进行的:
- 应用一个比例,使点随时间变小。
- 应用移动动画。
- 使用Remotion的
<Sequence>
组件在每个点的动画开始之间应用延迟。
src/Trail.tsxtsx
importReact from "react";import {AbsoluteFill ,Sequence } from "remotion";import {Move } from "./Move";export constTrail :React .FC <{amount : number;children :React .ReactNode ;}> = ({amount ,children }) => {return (<AbsoluteFill >{newArray (amount ).fill (true).map ((a ,i ) => {return (<Sequence from ={i * 3}><AbsoluteFill ><Move delay ={0}><AbsoluteFill style ={{scale :String (1 -i /amount ),}}>{children }</AbsoluteFill ></Move ></AbsoluteFill ></Sequence >);})}</AbsoluteFill >);};
src/Trail.tsxtsx
importReact from "react";import {AbsoluteFill ,Sequence } from "remotion";import {Move } from "./Move";export constTrail :React .FC <{amount : number;children :React .ReactNode ;}> = ({amount ,children }) => {return (<AbsoluteFill >{newArray (amount ).fill (true).map ((a ,i ) => {return (<Sequence from ={i * 3}><AbsoluteFill ><Move delay ={0}><AbsoluteFill style ={{scale :String (1 -i /amount ),}}>{children }</AbsoluteFill ></Move ></AbsoluteFill ></Sequence >);})}</AbsoluteFill >);};
在您的主组件中,现在用<Trail>
组件替换<Move>
组件:
src/Composition.tsxtsx
export constMyComposition = () => {return (<AbsoluteFill ><Background /><Trail amount ={4}><Shrinking ><Dot /></Shrinking ></Trail ></AbsoluteFill >);};
src/Composition.tsxtsx
export constMyComposition = () => {return (<AbsoluteFill ><Background /><Trail amount ={4}><Shrinking ><Dot /></Shrinking ></Trail ></AbsoluteFill >);};
这是带有复制点的动画应该看起来的样子:

复制标记并将其排列成一个圆
现在让我们创建一个<Explosion>
组件。它接受子元素并将它们渲染例如10次,并对每个实例应用旋转。值得一提的是,完整的旋转量为2π,而(i/AMOUNT)
表示0到1之间的因子。
src/Explosion.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";constAMOUNT = 10;export constExplosion :React .FC <{children :React .ReactNode ;}> = ({children }) => {return (<AbsoluteFill >{newArray (AMOUNT ).fill (true).map ((_ ,i ) => {return (<AbsoluteFill style ={{rotate : (i /AMOUNT ) * (2 *Math .PI ) + "rad",}}>{children }</AbsoluteFill >);})}</AbsoluteFill >);};
src/Explosion.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";constAMOUNT = 10;export constExplosion :React .FC <{children :React .ReactNode ;}> = ({children }) => {return (<AbsoluteFill >{newArray (AMOUNT ).fill (true).map ((_ ,i ) => {return (<AbsoluteFill style ={{rotate : (i /AMOUNT ) * (2 *Math .PI ) + "rad",}}>{children }</AbsoluteFill >);})}</AbsoluteFill >);};
将<Trail>
放在<Explosion>
组件中。您的主组件(src/Composition.tsx
)如下所示:
src/Composition.tsxtsx
export const MyComposition = () => {return (<AbsoluteFill> <Background /><Explosion><Trailamount={4}> <Shrinking><Dot /></Shrinking></Trail></Explosion></AbsoluteFill> );};
src/Composition.tsxtsx
export const MyComposition = () => {return (<AbsoluteFill> <Background /><Explosion><Trailamount={4}> <Shrinking><Dot /></Shrinking></Trail></Explosion></AbsoluteFill> );};
动画爆炸应该看起来像这样:

清理
到目前为止,您已经创建了一堆文件,让我们将大部分文件放在一个名为src/Dots.tsx
的文件中。将<Explosion>
和其子元素提取到一个名为Dots的新独立组件中。
src/Dots.tsxtsx
importReact from "react";import {Sequence } from "remotion";import {Dot } from "./Dot";import {Explosion } from "./Explosion";import {Shrinking } from "./Shrinking";import {Trail } from "./Trail";export constDots :React .FC = () => {return (<Explosion ><Trail amount ={4}><Shrinking ><Sequence from ={5}><Dot /></Sequence ></Shrinking ></Trail ></Explosion >);};
src/Dots.tsxtsx
importReact from "react";import {Sequence } from "remotion";import {Dot } from "./Dot";import {Explosion } from "./Explosion";import {Shrinking } from "./Shrinking";import {Trail } from "./Trail";export constDots :React .FC = () => {return (<Explosion ><Trail amount ={4}><Shrinking ><Sequence from ={5}><Dot /></Sequence ></Shrinking ></Trail ></Explosion >);};
用新的<Dots>
组件替换<Explosion>
:
tsx
export constMyComposition = () => {return (<AbsoluteFill ><Background /><Dots /></AbsoluteFill >);};
tsx
export constMyComposition = () => {return (<AbsoluteFill ><Background /><Dots /></AbsoluteFill >);};
动画本身没有任何变化:

添加心形和星星
为了使动画更加精彩,让我们添加一些不同颜色的星星和心形。为此,我们基本上需要重复之前的步骤。除了 <Dots>
组件外,在接下来的几个步骤中,我们将添加另外三个组件。
让我们从红色心形开始。首先,通过创建一个新文件 src/RedHeart.tsx
并返回一个居中的红色心形表情来渲染一个红色心形。
src/RedHeart.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constRedHeart :React .FC = () => {return (<AbsoluteFill style ={{justifyContent : "center",alignItems : "center",}}>❤️</AbsoluteFill >);};
src/RedHeart.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constRedHeart :React .FC = () => {return (<AbsoluteFill style ={{justifyContent : "center",alignItems : "center",}}>❤️</AbsoluteFill >);};
需要将 <Shrinking>
、<Move>
和 <Explosion>
这些效果应用到这个红色心形上。我们在一个名为 RedHearts 的新组件中实现这一点。
考虑到我们需要给 <RedHearts>
添加一个偏移量,否则它们会与 <Dots>
的位置相同。
我们通过给红色心形一个比点更大的半径,并应用 100px
的平移来改变位置。此外,我们给 <Move>
组件添加了一个短暂的 5 帧延迟:
src/RedHearts.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Explosion } from "./Explosion";import {Move } from "./Move";import {RedHeart } from "./RedHeart";import {Shrinking } from "./Shrinking";export constRedHearts :React .FC = () => {return (<Explosion ><Move delay ={5}><AbsoluteFill style ={{transform : `translateY(-100px)` }}><Shrinking ><RedHeart /></Shrinking ></AbsoluteFill ></Move ></Explosion >);};
src/RedHearts.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Explosion } from "./Explosion";import {Move } from "./Move";import {RedHeart } from "./RedHeart";import {Shrinking } from "./Shrinking";export constRedHearts :React .FC = () => {return (<Explosion ><Move delay ={5}><AbsoluteFill style ={{transform : `translateY(-100px)` }}><Shrinking ><RedHeart /></Shrinking ></AbsoluteFill ></Move ></Explosion >);};
我们做同样的事情来获得一些黄色心形在我们的动画中:
src/YellowHeart.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constYellowHeart :React .FC = () => {return (<AbsoluteFill style ={{justifyContent : "center",alignItems : "center",}}>💛</AbsoluteFill >);};
src/YellowHeart.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constYellowHeart :React .FC = () => {return (<AbsoluteFill style ={{justifyContent : "center",alignItems : "center",}}>💛</AbsoluteFill >);};
对于黄色心形,我们将通过应用 50px
的平移并给 <Move>
组件添加一个 20 帧的延迟来改变位置:
src/YellowHearts.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Explosion } from "./Explosion";import {Move } from "./Move";import {Shrinking } from "./Shrinking";import {YellowHeart } from "./YellowHeart";export constYellowHearts :React .FC = () => {return (<AbsoluteFill style ={{rotate : "0.3rad",}}><Explosion ><Move delay ={20}><AbsoluteFill style ={{transform : `translateY(-50px)`,}}><Shrinking ><YellowHeart /></Shrinking ></AbsoluteFill ></Move ></Explosion ></AbsoluteFill >);};
src/YellowHearts.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Explosion } from "./Explosion";import {Move } from "./Move";import {Shrinking } from "./Shrinking";import {YellowHeart } from "./YellowHeart";export constYellowHearts :React .FC = () => {return (<AbsoluteFill style ={{rotate : "0.3rad",}}><Explosion ><Move delay ={20}><AbsoluteFill style ={{transform : `translateY(-50px)`,}}><Shrinking ><YellowHeart /></Shrinking ></AbsoluteFill ></Move ></Explosion ></AbsoluteFill >);};
您的主要组合应该如下所示:

除了点和心形,让我们也添加星星。
创建一个新文件 src/Star.tsx
并返回一个居中的星星表情。
src/Star.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constStar :React .FC = () => {return (<AbsoluteFill style ={{justifyContent : "center",alignItems : "center",fontSize : 14,}}>⭐</AbsoluteFill >);};
src/Star.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";export constStar :React .FC = () => {return (<AbsoluteFill style ={{justifyContent : "center",alignItems : "center",fontSize : 14,}}>⭐</AbsoluteFill >);};
请注意,我们需要更改星星的定位,否则它们会在 <Dots>
的上方。
让我们给 <Trail>
一个 extraOffset
属性,这样星星就可以比点更向外开始。
星星的 extraOffset
为 100 导致了与红色心形相同的开始和结束的圆周。这是调整后的 <Trail>
:
src/Trail.tsxtsx
importReact from "react";import {AbsoluteFill ,Sequence } from "remotion";import {Move } from "./Move";export constTrail :React .FC <{amount : number;extraOffset : number;children :React .ReactNode ;}> = ({amount ,extraOffset ,children }) => {return (<AbsoluteFill >{newArray (amount ).fill (true).map ((a ,i ) => {return (<Sequence from ={i * 3}><AbsoluteFill style ={{translate : `0 ${-extraOffset }px`,}}><Move delay ={0}><AbsoluteFill style ={{scale :String (1 -i /amount ),}}>{children }</AbsoluteFill ></Move ></AbsoluteFill ></Sequence >);})}</AbsoluteFill >);};
src/Trail.tsxtsx
importReact from "react";import {AbsoluteFill ,Sequence } from "remotion";import {Move } from "./Move";export constTrail :React .FC <{amount : number;extraOffset : number;children :React .ReactNode ;}> = ({amount ,extraOffset ,children }) => {return (<AbsoluteFill >{newArray (amount ).fill (true).map ((a ,i ) => {return (<Sequence from ={i * 3}><AbsoluteFill style ={{translate : `0 ${-extraOffset }px`,}}><Move delay ={0}><AbsoluteFill style ={{scale :String (1 -i /amount ),}}>{children }</AbsoluteFill ></Move ></AbsoluteFill ></Sequence >);})}</AbsoluteFill >);};
Effects like <Shrinking>
, the new <Trail>
and <Explosion>
need to be applied to the star we created above. Additionally we also add some rotation. We do all of this in a new component called Stars:
src/Stars.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Explosion } from "./Explosion";import {Shrinking } from "./Shrinking";import {Star } from "./Star";import {Trail } from "./Trail";export constStars :React .FC = () => {return (<AbsoluteFill style ={{rotate : "0.3rad",}}><Explosion ><Trail extraOffset ={100}amount ={4}><Shrinking ><Star /></Shrinking ></Trail ></Explosion ></AbsoluteFill >);};
src/Stars.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Explosion } from "./Explosion";import {Shrinking } from "./Shrinking";import {Star } from "./Star";import {Trail } from "./Trail";export constStars :React .FC = () => {return (<AbsoluteFill style ={{rotate : "0.3rad",}}><Explosion ><Trail extraOffset ={100}amount ={4}><Shrinking ><Star /></Shrinking ></Trail ></Explosion ></AbsoluteFill >);};
这是几乎完成的烟花效果:

Slow motion effect
最后让我们给烟花应用一个慢动作效果。为此,创建一个名为 src/SlowedTrail.tsx
的新文件。它应该包含一个名为 Slowed 的组件和一个名为 remapSpeed()
的辅助函数,该函数将为烟花应用不同的速度级别。在下面的代码片段中,速度为 1.5 被应用到第 20 帧,之后速度减慢到 0.5。
src/SlowedTrail.tsxtsx
importReact from "react";import {Freeze ,interpolate ,useCurrentFrame } from "remotion";// remapSpeed() is a helper function for the component <Slowed> that takes a frame number and a speedconstremapSpeed = ({frame ,speed ,}: {frame : number;speed : (fr : number) => number;}) => {letframesPassed = 0;for (leti = 0;i <=frame ;i ++) {framesPassed +=speed (i );}returnframesPassed ;};export constSlowed :React .FC <{children :React .ReactNode ;}> = ({children }) => {constframe =useCurrentFrame ();constremappedFrame =remapSpeed ({frame ,speed : (f ) =>interpolate (f , [0, 20, 21], [1.5, 1.5, 0.5], {extrapolateRight : "clamp",}),});return <Freeze frame ={remappedFrame }>{children }</Freeze >;};
src/SlowedTrail.tsxtsx
importReact from "react";import {Freeze ,interpolate ,useCurrentFrame } from "remotion";// remapSpeed() is a helper function for the component <Slowed> that takes a frame number and a speedconstremapSpeed = ({frame ,speed ,}: {frame : number;speed : (fr : number) => number;}) => {letframesPassed = 0;for (leti = 0;i <=frame ;i ++) {framesPassed +=speed (i );}returnframesPassed ;};export constSlowed :React .FC <{children :React .ReactNode ;}> = ({children }) => {constframe =useCurrentFrame ();constremappedFrame =remapSpeed ({frame ,speed : (f ) =>interpolate (f , [0, 20, 21], [1.5, 1.5, 0.5], {extrapolateRight : "clamp",}),});return <Freeze frame ={remappedFrame }>{children }</Freeze >;};
在主组件中,将所有移动的点、心形和星星包装在组件 <Slowed>
中。正如你现在肯定已经注意到的那样,一切都是非常可组合的:
src/Composition.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Background } from "./Background";import {Dots } from "./Dots";import {RedHearts } from "./RedHearts";import {Slowed } from "./SlowedTrail";import {Stars } from "./Stars";import {YellowHearts } from "./YellowHearts";export constMyComposition = () => {return (<AbsoluteFill ><Background /><Slowed ><Dots /><RedHearts /><YellowHearts /><Stars /></Slowed ></AbsoluteFill >);};
src/Composition.tsxtsx
importReact from "react";import {AbsoluteFill } from "remotion";import {Background } from "./Background";import {Dots } from "./Dots";import {RedHearts } from "./RedHearts";import {Slowed } from "./SlowedTrail";import {Stars } from "./Stars";import {YellowHearts } from "./YellowHearts";export constMyComposition = () => {return (<AbsoluteFill ><Background /><Slowed ><Dots /><RedHearts /><YellowHearts /><Stars /></Slowed ></AbsoluteFill >);};
你的最终烟花应该是这样的:

添加你的 Animoji
作为本教程的最后一步,我们将在烟花上添加你的 Animoji。对于 Animoji,你需要拥有一部 iPhone 和一台 Mac。这是如何做到的: 在 iMessage 中的 iPhone 上,录制一个 Animoji 并将其发送给朋友。完成后,它也会出现在 Mac 上的 Messages 应用中。通过右键单击在那里下载你的 Animoji。完成后,创建你的 Animoji 的透明版本。只需按照以下步骤操作:
- 右键单击下载的 Animoji
- 选择 "Services"
- 选择 "Encode Selected Video Files"
- 在设置下拉菜单中选择 "Apple ProRes"
- 选中 "Preserve Transparency" 复选框。
将创建一个新的编码文件,给它一个简单的名称,比如 animoji.mov。
除了 Remotion 项目中的 src
文件夹外,创建一个名为 public
的新文件夹。将编码后的视频放入此文件夹。然后,你可以使用 FFmpeg 将编码后的视频转换为一系列帧:
-
将当前工作目录更改为
public
:cd public
-
使用此命令:
ffmpeg -i animoji.mov -pix_fmt rgba -start_number 0 frame%03d.png