Remotionで、海外YouTuberや海外ショート動画でよく見る“派手で速いテキストアニメーション”を作る方法を紹介します。
After Effectsのようなモーショングラフィックスは魅力的ですが、毎回手作業で作るのは大変です。
そこで便利なのが、ReactとTypeScriptで動画を作れる Remotion です。
この記事では、実際にRemotionで作成した縦型ショート動画向けの高速テキストアニメーションを題材にしながら、以下をまとめて解説します。
- Remotionでテキストアニメーション動画を作るメリット
- 海外風ショート動画っぽく見せる演出の考え方
- 実装の基本構成
- 派手で速い印象を出すための具体的なエフェクト
- XやYouTube Shorts向けに見せるコツ
「Remotionでかっこいい動画を作りたい」
「コードベースでショート動画の表現を量産したい」
「テキストアニメーションの作り方を知りたい」
という人にはかなり相性の良い内容です。
Remotionとは?
Remotion は、Reactを使って動画を作れるライブラリです。
普通の動画編集ソフトとは違い、コンポーネント・props・配列・条件分岐・アニメーションロジックをそのままコードで扱えます。
そのため、以下のような用途に強いです。
- SNS向けショート動画の量産
- テキスト差し替えが多い動画
- サービス紹介動画
- タイポグラフィ中心のモーション
- データ連動型の動画生成
特に、短尺のプロモーション動画やテキスト主体の縦動画はRemotionと非常に相性が良いです。
なぜRemotionでテキストアニメーションを作るのか?
Remotionでテキストアニメーションを作る大きな理由は、再利用性とスピードです。
After Effectsで1本ずつ作ると、見た目は良くても量産が難しくなります。
一方、Remotionなら以下のようなメリットがあります。
- テキストを配列で管理できる
- アニメーションを関数化できる
- 色やタイミングを再利用できる
- 縦動画・横動画の展開がしやすい
- 日本語版・英語版を切り替えやすい
つまり、「1回作って終わり」ではなく、「何本も展開できる動画テンプレート」を作れるのが強みです。
今回作った動画の方向性
今回の動画は、海外YouTuber風の派手で速いショート動画を意識しています。
特徴は次の通りです。
- 大きく太い文字
- 一瞬で切り替わるテンポ
- フラッシュ感のある演出
- グリッド背景
- スキャンライン風ノイズ
- グリッチっぽいズレ
- 強いスケールイン
- 短く刺さるコピー
こうした要素を入れることで、
「止まって見たくなる」「最初の1秒で引っかかる」 見た目になります。
動画構成の考え方
ショート動画で重要なのは、最初の数秒です。
今回はざっくり次の4ブロックで構成しました。
1. 最初のフック
最初に大きな文字を一気に出して、視線を止めます。
例:
- 映像で
- 一瞬で
- 惹きつける
2. スクロールを止める主張
次に、短く強いメッセージを出します。
例:
- 指を止めろ
- 最初の1秒で勝負が決まる
3. 要素の整理
動画の特徴をリズムよく並べます。
例:
- 太い文字
- 速いカット
- 強い一撃
- 残る導入
4. 最後の締め
Remotionで作ったことや、動画の用途を短く伝えます。
例:
- Remotionで魅せる
- Xで作り方を紹介したくなる縦ショート向けタイポ演出
Remotionで実装した主なエフェクト
今回の実装では、主に以下の演出を使っています。
スケールイン
文字が大きく飛び込んでくる動きです。
単純ですが、最も効きます。
spring() を使うことで、硬すぎず気持ちよく止まる動きになります。
フラッシュ
一定間隔で明るさを少しだけ揺らし、
画面全体にテンポ感を作ります。
派手にやりすぎると安っぽくなるので、軽く入れるのがコツです。
グリッチ風の横ズレ
文字の本体とは別に、色付きのズレレイヤーを少しだけ重ねると、
海外っぽい“荒さ”が出ます。
グリッド背景
情報量のない真っ黒背景だけだと弱いので、
遠近感のあるグリッドを敷いて空間を作ります。
スキャンライン / ノイズ
画面がデジタルに見える細いラインを入れるだけで、
静止画っぽさがかなり減ります。
アクセントバー
背景に斜めのラインや光の筋を流すと、
“何かが進んでいる感じ”が出せます。
実装の基本構成
Remotionでは、シーンごとに Sequence を分けると管理しやすいです。
イメージとしてはこんな構成です。
<Sequence from={0} durationInFrames={72}>
<WordBurst />
</Sequence>
<Sequence from={72} durationInFrames={66}>
<ImpactPanel />
</Sequence>
<Sequence from={138} durationInFrames={62}>
<SpeedList />
</Sequence>
<Sequence from={200} durationInFrames={55}>
<FinalLockup />
</Sequence>
この形にしておくと、
- シーン単位で作り直しやすい
- 長さの調整がしやすい
- パターン追加が簡単
- 日本語版と英語版を分けやすい
というメリットがあります。
このコードは、Remotionでシーンごとに動画をつなぐ基本構成です。
ただし、これだけでは演出は再現できません。
実際の見た目は、各シーンコンポーネントの中で spring() や interpolate() を使って作っています。
読者が再現できる記事にするなら、最低でも次の3つは必要です。
- Sequence でのシーン構成例
- WordBurst など1つの実装例
- spring() や interpolate() を使った文字アニメーション例
const progress = spring({
frame: frame - delay,
fps,
durationInFrames: 18,
config: {
damping: 12,
stiffness: 220,
mass: 0.6,
},
});
const scale = interpolate(progress, [0, 0.55, 1], [1.8, 0.92, 1]);
const x = Math.sin((frame + index * 3) * 0.7) * (1 - progress) * 60;
サンプルコード
最小構成で作る Remotion テキストアニメーション
1. コンポジション本体
import React from 'react';
import {AbsoluteFill, Sequence} from 'remotion';
import {WordBurst} from './WordBurst';
import {ImpactPanel} from './ImpactPanel';
import {SpeedList} from './SpeedList';
import {FinalLockup} from './FinalLockup';
export const FlashTextDemo: React.FC = () => {
return (
<AbsoluteFill style={{backgroundColor: '#050816', fontFamily: 'sans-serif'}}>
<Sequence from={0} durationInFrames={72}>
<WordBurst />
</Sequence>
<Sequence from={72} durationInFrames={66}>
<ImpactPanel />
</Sequence>
<Sequence from={138} durationInFrames={62}>
<SpeedList />
</Sequence>
<Sequence from={200} durationInFrames={55}>
<FinalLockup />
</Sequence>
</AbsoluteFill>
);
};
2. 文字が飛び込むシーン
import React from 'react';
import {AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
const words = ['映像で', '一瞬で', '惹きつける'];
export const WordBurst: React.FC = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
return (
<AbsoluteFill
style={{
justifyContent: 'center',
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
background:
'radial-gradient(circle at 50% 20%, rgba(103,232,249,0.18), transparent 30%), linear-gradient(180deg, #050816, #020617)',
}}
>
{words.map((word, index) => {
const progress = spring({
frame: frame - index * 6,
fps,
durationInFrames: 18,
config: {
damping: 12,
stiffness: 220,
mass: 0.6,
},
});
const scale = interpolate(progress, [0, 0.55, 1], [1.8, 0.92, 1]);
const y = interpolate(progress, [0, 1], [80, 0]);
const opacity = interpolate(progress, [0, 0.2, 1], [0, 1, 1]);
const glitchX = Math.sin((frame + index * 3) * 0.7) * (1 - progress) * 50;
return (
<div key={word} style={{position: 'relative', height: 170}}>
<div
style={{
position: 'absolute',
inset: 0,
color: '#67e8f9',
fontSize: 120,
fontWeight: 900,
opacity: opacity * 0.2,
transform: `translate(${glitchX + 10}px, ${y}px) scale(${scale})`,
filter: 'blur(8px)',
}}
>
{word}
</div>
<div
style={{
position: 'relative',
color: '#f8fafc',
fontSize: 120,
fontWeight: 900,
letterSpacing: -2,
opacity,
transform: `translate(${glitchX}px, ${y}px) scale(${scale})`,
textShadow: '0 0 30px rgba(255,255,255,0.18), 0 0 80px rgba(103,232,249,0.25)',
}}
>
{word}
</div>
</div>
);
})}
</AbsoluteFill>
);
};
3. 強いメッセージを見せるシーン
import React from 'react';
import {AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
export const ImpactPanel: React.FC = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const progress = spring({
frame,
fps,
durationInFrames: 20,
config: {
damping: 14,
stiffness: 180,
},
});
const scale = interpolate(progress, [0, 1], [0.9, 1]);
const y = interpolate(progress, [0, 1], [60, 0]);
return (
<AbsoluteFill
style={{
justifyContent: 'center',
alignItems: 'center',
display: 'flex',
padding: 80,
background:
'radial-gradient(circle at 50% 30%, rgba(244,114,182,0.16), transparent 30%), linear-gradient(180deg, #050816, #020617)',
}}
>
<div
style={{
border: '1px solid rgba(244,114,182,0.7)',
borderRadius: 32,
padding: 40,
width: '100%',
background: 'rgba(15,23,42,0.82)',
transform: `translateY(${y}px) scale(${scale})`,
boxShadow: '0 30px 100px rgba(0,0,0,0.45)',
}}
>
<div style={{color: '#f472b6', fontSize: 22, fontWeight: 800}}>フック</div>
<div
style={{
marginTop: 16,
color: '#f8fafc',
fontSize: 92,
lineHeight: 0.95,
fontWeight: 900,
letterSpacing: -4,
}}
>
指を
<br />
止めろ
</div>
<div style={{marginTop: 20, color: '#94a3b8', fontSize: 34}}>
最初の1秒で勝負が決まる。
</div>
</div>
</AbsoluteFill>
);
};
4. 特徴をリズムよく並べるシーン
import React from 'react';
import {AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
const items = ['太い文字', '速いカット', '強い一撃', '残る導入'];
export const SpeedList: React.FC = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
return (
<AbsoluteFill
style={{
justifyContent: 'center',
display: 'flex',
flexDirection: 'column',
gap: 24,
padding: 80,
background:
'radial-gradient(circle at 50% 30%, rgba(190,242,100,0.12), transparent 30%), linear-gradient(180deg, #050816, #020617)',
}}
>
{items.map((item, index) => {
const progress = spring({
frame: frame - index * 5,
fps,
durationInFrames: 18,
config: {
damping: 14,
stiffness: 200,
},
});
const x = interpolate(progress, [0, 1], [220, 0]);
const opacity = interpolate(progress, [0, 1], [0, 1]);
return (
<div
key={item}
style={{
transform: `translateX(${x}px)`,
opacity,
color: '#f8fafc',
fontSize: 86,
fontWeight: 900,
letterSpacing: -2,
}}
>
{item}
</div>
);
})}
</AbsoluteFill>
);
};
5. 最後の締め
import React from 'react';
import {AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
export const FinalLockup: React.FC = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const progress = spring({
frame,
fps,
durationInFrames: 18,
config: {
damping: 14,
stiffness: 180,
},
});
return (
<AbsoluteFill
style={{
justifyContent: 'center',
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
background:
'radial-gradient(circle at 50% 35%, rgba(103,232,249,0.18), transparent 25%), linear-gradient(180deg, #020617, #000)',
}}
>
<div
style={{
color: '#67e8f9',
fontSize: 24,
fontWeight: 800,
opacity: progress,
letterSpacing: 2,
}}
>
REMOTION 制作
</div>
<div
style={{
marginTop: 18,
color: '#f8fafc',
fontSize: 110,
lineHeight: 0.95,
fontWeight: 900,
textAlign: 'center',
letterSpacing: -4,
opacity: progress,
transform: `translateY(${interpolate(progress, [0, 1], [40, 0])}px)`,
}}
>
REMOTIONで
<br />
魅せる
</div>
<div
style={{
marginTop: 22,
color: '#94a3b8',
fontSize: 32,
opacity: interpolate(frame, [12, 28], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
}),
}}
>
縦ショート向けのタイポアニメーション
</div>
</AbsoluteFill>
);
};
このサンプルでは、Sequence で4つのシーンを時間順に並べています。
実際のアニメーションは、各シーンの中で spring() と interpolate() を使って作っています。
- Sequence
シーンを何フレーム目から何フレーム出すか管理する - spring()
文字の登場を気持ちよく見せる - interpolate()
拡大率、位置、透明度をフレームごとに変化させる
つまり、Sequence はタイムライン、spring() と interpolate() が見た目の本体です。
日本語でかっこよく見せるコツ
英語のテキストアニメーションをそのまま日本語化すると、だいたい崩れます。
理由は、日本語は情報密度が高く、詰め込むと重く見えるからです。
日本語で見栄えを良くするコツは次の通りです。
- 1画面あたりの文字数を減らす
- 1文ではなく短い語に分ける
- 行数を増やしすぎない
- 太めのゴシック体を使う
- 余白を大きく取る
- 説明しすぎない
つまり、
翻訳するのではなく、日本語向けに再設計する のが重要です。
Xで紹介するなら何を見せるべきか?
Xで「Remotionでこう作った」を見せる場合は、
完成動画だけでなく、仕組みが伝わる切り口があると強いです。
おすすめは次の3パターンです。
1. 完成動画を先に見せる
まず「おっ」と思わせることが大事です。
2. 演出要素を分解して見せる
例えば:
- 文字のスケールイン
- フラッシュ
- グリッド背景
- ノイズ
- グリッチ
3. コードで作っていることを伝える
「これ、After EffectsじゃなくてRemotionです」と伝えるだけで反応が変わります。
Remotionはこんな人に向いている
Remotionは特に次のような人に向いています。
- コードで動画を作りたいエンジニア
- SNS向けの短尺動画を量産したい人
- サービス紹介動画を仕組み化したい人
- テキスト差し替えを効率化したい人
- Web制作と動画制作をつなげたい人
「映像編集ソフトを毎回触るのは重いけど、見た目は妥協したくない」という人にはかなり合います。
まとめ
Remotionを使えば、海外YouTuber風の派手で速いテキストアニメーション動画をコードで作れます。
特にショート動画では、
- 最初の1秒の強さ
- 大きい文字
- 速いテンポ
- 光やノイズのレイヤー
- 背景の空間演出
このあたりをしっかり設計すると、一気に見栄えが良くなります。
After Effectsのような表現を完全に置き換えるわけではありませんが、
SNS向けの短尺動画やタイポグラフィ演出は、Remotionでかなり戦えます。
しかもコードなので、再利用もしやすいです。
「Remotionでかっこいい動画を作りたい」
「ショート動画向けの演出を量産したい」
「テキストアニメーションを仕組み化したい」
なら、かなり有力な選択肢です。
よくある質問
Remotionでテキストアニメーションは簡単に作れますか?
基本的なスライドや拡大縮小なら簡単です。
凝った見た目にするには、タイミング設計とレイヤー構成が重要です。
Remotionは日本語動画にも向いていますか?
向いています。
ただし英語の演出をそのまま移すのではなく、日本語向けの文字量と余白設計が必要です。
RemotionとAfter Effectsはどちらが良いですか?
単発の自由な演出ならAfter Effectsが強いです。
量産・差し替え・テンプレート化ならRemotionが強いです。
