text-animation-copier について
text-animation-copierは、動画例のテキストアニメーションをRemotionのReactコンポーネントとして再現するスキルです。フレーム分析から動きの設計、生成、Remotion Studioでのテストまでを支援します。
主な機能
- 01動画フレームの抽出と確認
- 02テキストのタイミングと効果の分析
- 03Remotion Reactコンポーネントの生成
- 04Remotion Studioでの登録とテスト
- 05段階式や文字単位のアニメーション再現
活用シーン
- 01動画クリップのタイトルアニメーション再現
- 02動画のタイムコードに合わせた動きの調整
- 03スタガーや複数段階のテキスト効果作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ andchir/ remotion-animations --skill text-animation-copierインストール後、Claude Code で/text-animation-copierを入力して読み込まれたか確認します。
詳細
Remotion 向けテキストアニメーションの複製
動画の例からテキストアニメーションを分析し、正確なタイミング、スタイル、エフェクトを備えた Remotion の React コンポーネントとして再現します。
クイックスタート
前提条件
このスキルを使用する前に、以下を確認してください。
- ffmpeg がインストールされていること - 動画のフレーム抽出に必要です
- Remotion プロジェクトがセットアップされていること - 動作する remotion-animations リポジトリ
- 動画の URL またはファイルパス - アニメーションを含む動画への直接リンク、またはローカルパス
基本的なワークフロー
ユーザーから複製対象のテキストアニメーションを含む動画が提供された場合:
- 動画をダウンロードしてフレームを抽出します(
claude-skills/video-viewingを使用) - キーフレームを調べてアニメーションを分析します
- アニメーションのプロパティ(タイミング、エフェクト、位置、スタイル)を特定します
- アニメーションを再現する Remotion コンポーネントを生成します
- Remotion Studio でアニメーションをテストして調整します
詳細な手順
ステップ 1:動画をダウンロードしてフレームを抽出する
video-viewing スキルを使って動画をダウンロードし、フレームを抽出します。
python scripts/download_video.py "VIDEO_URL" -f
動画を /mnt/user-data/outputs/ にダウンロードし、分析用のフレームを抽出します。
別の方法: ユーザーからローカル動画ファイルのパスが提供された場合は、ffmpeg を直接使用します。
# Extract frames at 1 frame per second
ffmpeg -i path/to/video.mp4 -vf fps=1 /tmp/frames/frame-%04d.png
# Extract frames at specific time interval (e.g., 00:07 to 00:13)
ffmpeg -i path/to/video.mp4 -ss 00:07 -to 00:13 -vf fps=2 /tmp/frames/frame-%04d.png
ステップ 2:フレームを調べてアニメーションを分析する
通常、ユーザーは時間範囲(例:「00:07 - 00:13」)を指定します。その範囲のフレームを抽出して分析します。
- アニメーションの開始フレームと終了フレームを特定します
- 主要なトランジションポイント(アニメーションの動作が変化するタイミング)を調べます
- 背景の動画は無視し、テキスト要素のみに集中します
- 以下の項目について観察結果を記録します。
- テキストの内容と位置
- フォントファミリー、サイズ、太さ、色
- アニメーションの種類(フェード、スライド、拡大縮小、回転、反転など)
- タイミングとイージングカーブ
- 複数段階のアニメーション(例:バーの塗りつぶし後にテキストを表示)
- 特殊効果(3D トランスフォーム、シャドウ、グロー、パーティクル)
ステップ 3:アニメーションのプロパティを特定する
フレーム分析に基づき、次の主要なプロパティを記録します。
タイミング設定
- Duration:アニメーション全体の長さ(秒/フレーム)
- FPS:動画のフレームレート(ウェブ動画では通常 30fps)
- 重要なタイミング:重要なトランジションのフレーム番号
- イージング:イージングカーブの種類(linear、ease-in-out、cubic、bezier)
タイミング構成の例:
const TIMING = {
PHASE_1_START: 0,
PHASE_1_END: 45,
PHASE_2_START: 48,
PHASE_2_END: 90,
HOLD_END: 180,
};
テキストのスタイル
- フォントファミリー:Arial、Helvetica、カスタムフォント
- フォントサイズ:ピクセル単位
- フォントの太さ:normal、bold、300-900
- 色:Hex または rgba の値
- 文字間隔:文字間に追加する間隔
- テキストの配置:left、center、right
位置
- 配置:center、top-left、bottom-left など
- オフセット値:端からの距離(ピクセル単位)
- レスポンシブな配置:中央揃えにはビューポートの幅/高さを使用します
アニメーションエフェクト
一般的なテキストアニメーションのパターン:
1. フェードイン/アウト
const opacity = interpolate(
frame,
[START_FRAME, END_FRAME],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
}
);
2. スライドイン/アウト
const translateX = interpolate(
frame,
[START_FRAME, END_FRAME],
[-500, 0], // from left to center
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
}
);
3. 拡大縮小アニメーション
const scale = interpolate(
frame,
[START_FRAME, END_FRAME],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.elastic(1),
}
);
4. 3D 回転/反転
const rotateY = interpolate(
frame,
[START_FRAME, END_FRAME],
[0, 360],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.ease),
}
);
// Apply with CSS transform
transform: `rotateY(${rotateY}deg)`,
transformStyle: "preserve-3d",
perspective: "1000px"
5. バーの塗りつぶしアニメーション
const barProgress = interpolate(
frame,
[BAR_START, BAR_END],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}
);
// Apply to width
width: `${barProgress * 100}%`
6. スタガーアニメーション(複数の文字/単語向け)
// Each letter starts with a delay
const letterStart = BASE_START + index * STAGGER_DELAY;
const letterEnd = letterStart + ANIMATION_DURATION;
const letterOpacity = interpolate(
frame,
[letterStart, letterEnd],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
7. スプリング物理
const scale = spring({
frame: frame - START_FRAME,
fps: 30,
config: {
damping: 10,
stiffness: 100,
mass: 0.5,
},
});
ステップ 4:Remotion コンポーネントを生成する
次のパターンに従って、src/animations/text-animation-N/ に新しい React コンポーネントを作成します。
コンポーネント構造のテンプレート
import React from "react";
import {
AbsoluteFill,
useCurrentFrame,
useVideoConfig,
interpolate,
Easing,
spring,
} from "remotion";
// Animation timing configuration (in frames, at 30fps)
// Reference video time range: HH:MM:SS - HH:MM:SS
const TIMING = {
ANIMATION_START: 0,
ANIMATION_END: 60,
// Add more timing points as needed
};
// Configuration constants
const TEXT = "YOUR TEXT HERE";
const FONT_SIZE = 48;
const FONT_FAMILY = "Arial, sans-serif";
const TEXT_COLOR = "#FFFFFF";
export const TextAnimationN: React.FC = () => {
const frame = useCurrentFrame();
const { width, height } = useVideoConfig();
// Calculate animation values based on current frame
const opacity = interpolate(
frame,
[TIMING.ANIMATION_START, TIMING.ANIMATION_END],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.ease),
}
);
return (
<AbsoluteFill
style={{
backgroundColor: "transparent", // Always transparent for overlays
}}
>
{/* Your animation elements here */}
<div
style={{
fontFamily: FONT_FAMILY,
fontSize: `${FONT_SIZE}px`,
color: TEXT_COLOR,
opacity: opacity,
// Add positioning, transforms, etc.
}}
>
{TEXT}
</div>
</AbsoluteFill>
);
};
重要な要件
- 解像度:常に 1920x1080 を使用します(Root.tsx で設定済み)
- 透明な背景:
backgroundColor: "transparent" - 中央配置:中央揃えには
width/2とheight/2を使用します - タイミングの精度:元の動画のタイミングにできるだけ合わせます
- クリーンなコード:各アニメーション段階を説明するコメントを追加します
ステップ 5:コンポジションを登録する
新しいアニメーションを src/Root.tsx に追加します。
import { TextAnimationN } from "./animations/text-animation-N/TextAnimationN";
<Composition
id="TextAnimationN"
component={TextAnimationN}
durationInFrames={180} // Adjust based on animation length
fps={30}
width={1920}
height={1080}
defaultProps={{}}
/>
ステップ 6:Remotion Studio でテストする
npm start
Remotion Studio が http://localhost:3000 で開き、次のことができます。
- アニメーションをリアルタイムでプレビューする
- フレームをスクラブしてタイミングを確認する
- 元の動画と比較する
- 値を調整してすぐに結果を確認する
ステップ 7:アニメーションをレンダリングする
アニメーションに満足したら、次を実行します。
# Render as WebM with transparency (recommended)
npm run render:text-animation-N
# Or add custom render script to package.json:
npx remotion render src/index.ts TextAnimationN out/text-animation-N.webm --codec vp9 --pixel-format yuva420p
高度なテクニック
1 文字ずつのアニメーション
各文字を個別にアニメーションさせる場合:
const Letter: React.FC<{
char: string;
index: number;
totalLetters: number;
}> = ({ char, index, totalLetters }) => {
const frame = useCurrentFrame();
// Stagger each letter's animation
const letterDelay = index * 3; // 3 frames delay per letter
const letterStart = TIMING.ANIMATION_START + letterDelay;
const opacity = interpolate(
frame,
[letterStart, letterStart + 15],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return (
<span style={{ opacity }}>
{char}
</span>
);
};
// In main component:
const letters = TEXT.split("").map((char, i) => (
<Letter key={i} char={char} index={i} totalLetters={TEXT.length} />
));
複数段階のアニメーション
複数のフェーズが順番に続く複雑なアニメーションの場合:
// Phase 1: Slide in
const slideProgress = interpolate(
frame,
[TIMING.SLIDE_START, TIMING.SLIDE_END],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
}
);
// Phase 2: Scale pulse (starts after slide completes)
const scaleProgress = interpolate(
frame,
[TIMING.SCALE_START, TIMING.SCALE_END],
[1, 1.2],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.ease),
}
);
// Phase 3: Fade out
const fadeOutProgress = interpolate(
frame,
[TIMING.FADEOUT_START, TIMING.FADEOUT_END],
[1, 0],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
}
);
// Combine all phases
const translateX = slideProgress * width;
const scale = frame >= TIMING.SCALE_START ? scaleProgress : 1;
const opacity = frame >= TIMING.FADEOUT_START ? fadeOutProgress : 1;
背景エフェクト
アニメーション背景を使ったテキスト(TextAnimation2 など)の場合:
// Background appears behind text with 3D rotation
<div
style={{
position: "absolute",
width: charWidth + 20,
height: fontSize + 20,
backgroundColor: BACKGROUND_COLOR,
transform: `rotateY(${bgRotateY}deg) scaleX(${bgScaleX})`,
transformStyle: "preserve-3d",
opacity: bgOpacity,
zIndex: -1, // Behind text
}}
/>
カスタムイージング関数
タイミングを正確に合わせる場合:
// Built-in easing options:
Easing.linear // Constant speed
Easing.ease // Gentle start and end
Easing.in(Easing.quad) // Accelerate
Easing.out(Easing.quad) // Decelerate
Easing.inOut(Easing.cubic) // Smooth S-curve
Easing.bezier(0.25, 0.1, 0.25, 1) // Custom cubic bezier
// Available easing functions:
// quad, cubic, poly, sin, exp, circle, back, bounce, elastic
技術リファレンス
Remotion の主要なフック
useCurrentFrame():現在のフレーム番号を返しますuseVideoConfig():{ fps, width, height, durationInFrames }を返しますinterpolate(value, inputRange, outputRange, options):値を滑らかにマッピングしますspring(options):物理法則に基づくアニメーションを作成しますSequence:オフセットを指定して複数のアニメーションを重ねます
Remotion の基本コンポーネント
<AbsoluteFill>:画面全体に配置するコンテナ<Sequence from={frame} durationInFrames={frames}>:時間をずらしたアニメーション<Audio>:BGM/効果音<Video>:背景動画を埋め込みます<Img>:静止画またはアニメーション画像
CSS の変形プロパティ
3D エフェクトには、次の変形プロパティを使用します。
perspective: 1000px; /* Enable 3D space */
transformStyle: preserve-3d; /* Maintain 3D in children */
backfaceVisibility: hidden; /* Hide back of element */
/* Transform functions: */
transform: translateX(px) translateY(px) translateZ(px)
rotateX(deg) rotateY(deg) rotateZ(deg)
scale(factor) scaleX() scaleY()
skewX(deg) skewY(deg);
よく使われるアニメーションパターン
1. テキストのローワーサード(TextAnimation1 など)
- 左から右へ広がる色付きバー
- バーのアニメーション完了後にテキストを表示
- 画面の隅(通常は左下)に配置
2. 3D 回転しながら飛び込むテキスト(TextAnimation2 など)
- 画面外からテキストが飛び込む
- 移動しながら各文字が 3D 回転する
- 文字の背後で背景ボックスが回転して所定の位置に収まる
- 視覚的な面白さを出すためにタイミングをずらす
3. タイプライターエフェクト
const visibleChars = Math.floor(
interpolate(
frame,
[START, END],
[0, TEXT.length],
{ extrapolateRight: "clamp" }
)
);
return <div>{TEXT.substring(0, visibleChars)}</div>;
4. バウンスイン
const bounceScale = spring({
frame: frame - START_FRAME,
fps: 30,
config: {
damping: 12,
stiffness: 200,
mass: 0.5,
},
});
5. グリッチエフェクト
const glitchOffset = Math.random() * 10 - 5;
const glitchActive = frame % 10 === 0; // Every 10 frames
return (
<div style={{
transform: glitchActive
? `translate(${glitchOffset}px, ${glitchOffset}px)`
: 'none',
}}>
{TEXT}
</div>
);
ベストプラクティス
1. タイミングの正確さ
- 時間をフレームに変換する:30fps の場合、1 秒 = 30 フレームです
- 元のタイミングに合わせる:動画のタイムコードを使って TIMING 定数を設定します
- 遅延を考慮する:見た目が自然につながるようにアニメーションのタイミングをずらします
2. パフォーマンス
- フレームごとの複雑な計算を避ける:可能な場合は事前に計算します
- 手動計算より interpolate を使う:最適化されており、エッジケースにも対応します
- 再レンダリングを最小限にする:コンポーネントのロジックをシンプルに保ちます
3. コードの整理
- 定数を先頭にまとめる:TIMING、COLORS、SIZES を一か所にまとめます
- フェーズにコメントを付ける:各アニメーションフェーズの処理を記録します
- 再利用可能なコンポーネント:繰り返し使うパターン(Letter コンポーネントなど)を切り出します
4. 見た目の忠実さ
- フォントをできるだけ合わせる:ウェブセーフフォントを使うか、カスタムフォントを読み込みます
- 色の正確さ:動画のフレーム上でカラーピッカーを使います
- 位置の正確さ:動画のフレーム上で距離を測定します
5. テストのワークフロー
- Remotion Studio でテストする:すぐに視覚的なフィードバックを得られます
- 並べて比較する:元の動画をアニメーションと並べて再生します
- すべてのフレームを確認する:スクラブして滑らかなトランジションを確認します
- レンダリングして確認する:最終的なレンダリング結果はプレビューと異なる場合があります
トラブルシューティング
アニメーションのタイミングが合わない
- FPS が元の動画と一致していることを確認します(通常は 30fps)
- TIMING 定数が正確であることを確認します
console.log(frame)を使ってフレーム値をデバッグします
テキストの位置がずれている
useVideoConfig()のwidthとheightを再確認します- 中央揃えの計算を確認します:
width/2 - textWidth/2 - Remotion Studio でさまざまなビューポートサイズをテストします
アニメーションがカクつく
- コンポジションの
durationInFramesを増やします - イージング関数が滑らかであることを確認します(線形ではないこと)
- フレームレートが一定であることを確認します(30fps)
3D 変形が機能しない
- 親要素に
perspective: "1000px"を追加します transformStyle: "preserve-3d"を含めます- ブラウザーが 3D 変形に対応していることを確認します
テキストが表示されない
opacityが 0 になっていないことを確認しますzIndexの重なり順を確認します- 背景との色のコントラストを確認します
- テキストが表示されるタイミングがフレーム範囲に含まれていることを確認します
ワークフローの例
例 1:テキストをシンプルにフェードインする
ユーザーが提供するもの:00:03 から 00:05 にテキストがフェードインする動画
- 動画をダウンロードし、フレームを抽出します
- フレームを分析します:「HELLO」というテキストが不透明度 0% から 100% へフェードします
- フレームを計算します:3 秒から 5 秒は、フレーム 90 から 150 です(30fps の場合)
- フェードの補間を使ってコンポーネントを作成します
- テストしてレンダリングします
例 2:順番に表示される複数行のテキスト
ユーザーが提供するもの:00:10 から 00:15 に 3 行のテキストが順番に表示される動画
- 10~15 秒のフレームを抽出します
- 各行の表示タイミングを特定します:1 行目は 10 秒、2 行目は 12 秒、3 行目は 14 秒に表示されます
- 各行のタイミングを計算します(30fps)
- それぞれのタイミングをずらした 3 つのテキスト要素を含むコンポーネントを作成します
- 順番に表示される間隔が元の動画と一致することを確認します
- レンダリングします
例 3:複雑な複数段階のアニメーション
ユーザーが提供するもの:00:20 から 00:30 にテキストがスライドインし、回転してからスライドアウトする動画
- 0.5 秒ごとにフレームを抽出します
- 各段階を特定します:
- 段階 1(20~23 秒):左からスライドインします
- 段階 2(23~26 秒):360 度回転します
- 段階 3(26~30 秒):右へスライドアウトします
- 各段階の
TIMING定数を作成します - 3 つの独立した補間を実装します
- スタイルオブジェクト内で変換を組み合わせます
- 各段階間の遷移が滑らかであることを確認します
- レンダリングして比較します
他のスキルとの連携
このスキルは、以下と組み合わせると最も効果的です:
claude-skills/video-viewing:動画のダウンロードとフレームの抽出に使用しますremotion-best-practices:高度な Remotion のテクニックに使用します- 動画編集の知識:タイミング、イージング、キーフレームについて理解します
出力チェックリスト
テキストアニメーションの再現を納品する際は、以下を確認します:
-
src/animations/text-animation-N/にコンポーネントを作成済み -
src/Root.tsxに登録済み - 解像度が 1920x1080
- 背景が透明
- 指定がある場合、テキストが中央揃え
- タイミングが元の動画と一致
-
TIMING定数にコメントで説明を記載済み - コードが整理され、適切にコメントを記載済み
- Remotion Studio でテスト済み
- package.json にレンダリングスクリプトを追加済み(任意)
- 元の動画の時間範囲をコメントに記載済み
コマンドのクイックリファレンス
# Download video with frame extraction
python scripts/download_video.py "VIDEO_URL" -f
# Start Remotion Studio for testing
npm start
# Type check the code
npm run typecheck
# Render animation
npx remotion render src/index.ts TextAnimationN out/output.webm --codec vp9 --pixel-format yuva420p
# Extract specific time range from video
ffmpeg -i input.mp4 -ss 00:07 -to 00:13 -vf fps=2 output-%04d.png
便利なリソース
- Remotion のドキュメント:https://www.remotion.dev/docs
- Remotion イージングビジュアライザー:https://www.remotion.dev/docs/easing
- Cubic Bezier ジェネレーター:https://cubic-bezier.com/
- CSS Transform リファレンス:https://developer.mozilla.org/en-US/docs/Web/CSS/transform
概要
このスキルを使うと、動画内のテキストアニメーションを体系的に分析し、再利用可能な Remotion コンポーネントとして再現できます。重要なのは、注意深く観察し、タイミングを正確に変換し、Remotion の強力な補間機能とアニメーション機能を活用することです。
ピクセル単位で完全に一致させることよりも、元のアニメーションのタイミングと見た目の印象を再現することを常に優先してください。イージングやタイミングに多少の違いがあっても、アニメーションをより自然に感じさせながら、元の表現の本質を捉えることができます。