mcpField
F
fframes-video

fframes-video

github.com/dmtrkovalenkoクリエイティブ・メディア3.1k199 回インストール1 日前に更新
リポジトリ

fframes-video について

fframes-videoは、Rustライブラリfframesで動画を作る開発者向けのスキルです。シーン単位のアニメーション、音声の配置、プレビュー、品質確認の流れを扱います。

主な機能

  1. 01Rustコードによる動画フレーム生成
  2. 02シーンとタイムラインによるアニメーション構成
  3. 03オーディオマップによる音声配置
  4. 04GPUレンダリングでのプレビュー
  5. 05フレーム、コンタクトシート、ラウドネスの確認

活用シーン

  1. 01単一ショットや複数シーンの動画制作
  2. 02音楽に合わせたアニメーション設計
  3. 03動画のレイアウトと動きの確認
  4. 04完成動画の書き出し

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dmtrkovalenko/fframes --skill fframes-video

インストール後、Claude Code で/fframes-videoを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api.md
audio.md
3d.md
design.md

詳細

fframes で動画を作成する

fframes は、コードから動画をレンダリングする Rust ライブラリです。動画は render_frame(frame) -> Svgr メソッドを持つ Rust の構造体です。このメソッドは各フレームについて、svgr! マクロ({rust expressions} を含む SVG マークアップ)で構築した SVG ツリーを返します。シーンでタイムラインを分割し、timeline! とスプリングで値をアニメーションさせ、オーディオマップでサウンドを配置し、ffmpeg で結果をエンコードします。

各プロジェクトにはコマンドライン(fframes::cli)が用意されています。動画のレンダリング、リアルタイムプレビューウィンドウの表示、フレーム、コンタクトシート、ラウドネス値を読み取り可能なファイルとして確認するなど、あらゆる操作に使用できます。デザインを始める前に references/design.md を、コードを書くときは references/api.md を、サウンドについては references/audio.md を、3D ショットについては references/3d.md(fframes::three_d)を読んでください。

提供された動画に合わせる場合は、まず references/design.md のリファレンス分析に関するガイダンスに従ってください。カット、ペース配分、モーションは以下のデザイン既定値より優先されます。速い編集や意図的な黒フレームも、求められる仕上がりの一部である可能性があります。

何よりも先に守るべき2つのルール

コードを書く前に計画する

テンプレートを開いて、すぐにアニメーションを始めてはいけません。まず、次のことを行います。

  1. 概要を明確にします。誰がどこで見るのか(プラットフォームによって形式と長さが決まります)、視聴者に覚えてもらうべきことは何か、どのようなトーンにするか、利用できる素材(ロゴ、製品の画像、映像、音楽、ナレーション)は何かを確認します。不足していて重要な情報はユーザーに尋ねてください。製品の事実、数値、引用を決して捏造してはいけません。
  2. 音楽やナレーションに合わせて動画を編集する場合は、最初にサウンドを選びます。テンポ、ビート、フレーズによって、ほかのすべてのタイミングが決まります。
  3. まずモーションデザインを計画し、サウンドのピークに同期させて、独自の一連の流れを作ります。要素がどこから現れ、どのように変形するかを考えます。各シーンに独自のモーションデザインを取り入れ、個性と洗練さを感じられるようにしてください。動画がスライドショーのように見えてはいけません。
  4. 完成した動画を見る人がどのように感じるかを考え、それに応じて、流れ、テンポ、ビート、モーション、色など、デザインのすべてを調整します。
手抜きをしない

手抜き動画とは、既定の選択肢だけで作られた動画です。テキストを変えるだけでどんな製品にも使えて、視聴者は一秒でそれを見抜きます。ユーザーから求められない限り、次のようなものを納品してはいけません。

  • テンプレートの残り物:スターターレイアウト、色、フォント、装飾、プレースホルダーテキスト、偽のロゴ、捏造した数値。
  • ビートの連打:ビートごとにフレーム全体をズーム、振動、点滅させること。ビートには小さな要素(線、単語、きらめき)を同期させ、フレーム全体を変えるのは数回のカットだけにします。
  • すべてに同じモーションを使うこと:すべての要素を同じイージングと時間で40 px上からフェードインさせること。
  • 動きのないシーン:何も動かないまま、一つの要素が現れ、静止し、消えるだけのシーン。
  • ありきたりなコピー:「Introducing」、「Unleash」、「Seamless」、「Next-level」や、3語のキャッチフレーズ(「Fast. Simple. Powerful.」)。画面上のテキストは、人が実際に話すような言葉で書きます。
  • テキスト全般:テキストの量は抑え、要点を絞ります。

代わりに、すべての要素に題材と結び付いた理由を持たせ、理由のないものは取り除きます。言葉よりも細部とモーションに力を注ぎます。二次的な動き、時間差をつけた登場、線を描く動き、互いに反応するオブジェクト、カットをまたいで引き継がれる要素などを取り入れます。ユーザーに見せる前に、フレームの一覧を確認し、テキストを変えるだけで別の製品にも使える動画になっていないか考えます。そうなっている場合は、色ではなくアイデアを変えてください。

1. インストール

https://rustup.rs から Rust をインストールし、続いて ffmpeg のビルドに必要なシステムライブラリをインストールします。

# macOS
brew install pkg-config ffmpeg x264 x265 opus nasm ninja
# Debian / Ubuntu
sudo apt-get install -y yasm nasm ffmpeg libx264-dev libx265-dev libopus-dev libclang-dev clang ninja-build libvpx-dev libasound2-dev
# Arch
sudo pacman -S ninja yasm nasm ffmpeg x264 x265 opus clang

Windows では、代わりにビルド済みの FFmpeg 9 共有ビルドをリンクします(FFMPEG_DIR に BtbN/FFmpeg-Builds の展開済み ffmpeg-n9.0-latest-win64-gpl-shared ビルドを設定し、その bin を PATH に追加します。winget install LLVM.LLVM で LLVM をインストールし、LIBCLANG_PATH を設定してください)。詳しくは fframes の README を参照してください。

2. プロジェクトを作成する

curl -fsSL https://raw.githubusercontent.com/dmtrKovalenko/fframes/main/scripts/new-video.sh | bash -s -- my-video --yes
# or install the generator once and use it directly:
cargo install --locked cargo-fframes
cargo fframes new my-video --format landscape --fps 30 --yes

オプション:--template single-scene|multi-scene、--format landscape|portrait|square|uhd、 --fps、--title、--backend、--dir。プロジェクトは、インストール済みの cargo-fframes に対応する fframes リリースに依存します。--git を指定すると、代わりにリポジトリの main ブランチが使用されます。入力待ちにならないよう、必ず --yes を指定してください。

テンプレート:

  • single-scene(デフォルト):シーンが1つです。すべてのフォーマットに対応します。ワンショットのクリップ、タイトルカード、縦向き動画には、まずこちらを使ってください。
  • multi-scene:シーンが2つです。複数のシーンがあるものには、まずこちらを使ってください。対応するのは landscape と uhd のみです。

テンプレートの内容は、API を示すプレースホルダーコードです。動画の依頼内容に合わせたデザインにするため、レイアウト、色、フォント、装飾を置き換えてください。

Skia GPU バックエンド(デフォルト)を使用してください。 cargo fframes new は、macOS では Metal、Linux と Windows では Vulkan 上の Skia を選択します。CPU バックエンドより約10倍高速にレンダリングでき、リアルタイムの preview ウィンドウも使えます。macOS と Linux では、初回ビルド時にビルド済みの Skia と ffmpeg がダウンロードされ、Rust の依存関係のみがコンパイルされます(約1分。他のターゲットや metal と vulkan の両方を指定した場合は、Skia のソースコードからのコンパイルに約20分かかります)。すぐに実行し、動作中に動画を作成してください。

cd my-video && cargo build --release        # run in the background, the first build is the slow one

--backend cpu は Skia を必要としませんが、プレビューウィンドウはありません。GPU がない場合にのみ選択してください。

プロジェクトは、生成された状態でレンダリングされます。

my-video/
  src/lib.rs        # the video (from the template)
  src/main.rs       # the command line
  media/            # fonts, images and audio compiled into the binary (one starter font)
  README.md         # the commands below

以下の各コマンドは cargo run --release -- <command> です。短いシェル関数を定義してください(R="cargo run --release --" のような変数は、zsh(macOS のシェル)では単語に分割されません)。

R() { cargo run --release -- "$@"; }

3. ワークフロー

このスキルを使うときは、テストを一切書かないでください。 単体テスト、統合テスト、スナップショットテスト、ビジュアルリグレッションテスト、テストモジュール、テストハーネスは作成しないでください。inspect、レンダリングしたフレーム、コンタクトシート、音声チェック、ネイティブプレビューを使って動画を検証してください。

レンダリングではなく、プレビューしてください。 動画で GPU レンダーバックエンドを使用し、このマシンで GPU が利用できる場合は、変更のたびに動画を再レンダリングするのではなく、ネイティブプレビューを実行するか、ユーザーにコマンドを提示してください。変更内容のレビューを依頼する準備ができたら、次の手順に従ってください。

  1. 実際のプロジェクトパスとパッケージ名を使った完全なコマンドを、コピー可能なシェルコードブロックで提示してください。ユーザーが $R ヘルパーを定義する必要がないようにしてください。例:
    cd /absolute/path/to/fframes && cargo run --release -p my-video -- preview 0s
  2. そのプレビューを実行するかどうかを、ユーザーに明示的に確認してください。すでにプレビューの起動または更新を許可されている場合は、コマンドを提示し、その許可の範囲内で作業を続けてください。

変更を依頼された後は、変更箇所の少し前、またはその時点の秒数を開始時刻として指定し、登場やトランジションを確認できるだけの先行時間を確保してください。たとえば preview 8.5s とすれば、冒頭から再生し直さずに、約9秒付近の変更をユーザーが確認できます。表示されるセクションも伝えてください。ユーザーが最終エクスポートを依頼した場合は動画全体をレンダリングしてください。その依頼がすでに明確な場合は、再確認を求めないでください。

変更のたびに:

  1. $R timeline は、各シーンのフレーム範囲と時間範囲、およびすべての音声トラックを一覧表示します。 ピクセルを見る前に、ここで構成とテンポを確認してください。
  2. $R inspect は、0.25 秒ごとのフレームに加え、各シーンの最初と最後のフレームをチェックします。 画像、フォント、グリフの欠落、キャンバスの端で切れているテキスト、無効な SVG(サイズがゼロの長方形、不正な半径)、壊れたトランスフォーム、パニックを、 それぞれ発生時刻とシーンとともに報告します。エラーがある場合は終了コード 2 で終了します。 報告された問題はすべて修正してください。シーンの最初の数フレームにだけ表示される警告は、 たいていは登場時のものです。ストリップで確認してください。
  3. $R strip <scene or range> -n 12 は、間隔を均等にしたフレームをラベル付きの 1 枚の画像にまとめた コンタクトシート(strip.png)を書き出します。画像ツールで開いてください。レイアウト、 リズム、動きを判断する最も速い方法です。$R strip 2s,5s,9s では、指定した時刻を横に並べます。
  4. $R frame Intro@end,Outro@50% は、詳細チェック(タイポグラフィ、位置合わせ、コントラスト)用に、 フルサイズの PNG を frames/ に書き出し、そのフレームで見つかった問題を表示します。 細部(要素間の接触、エッジ、小さな図形)は、縮小されたフレームではなく、鮮明に拡大した クロップ画像で確認してください。例:$R frame 3s --crop 1100,520,240,120(動画のピクセル単位で指定し、 幅約 960 px に拡大)。--ids を指定すると、id のあるすべての要素を囲んで名前を表示するため、 どの図形かを特定できます。
  5. $R onion "[email protected]@1s" -n 6 は、フレームを 1 枚の画像(onion.png)に重ねて、 動きの軌跡と間隔(イージング、オーバーシュート、時間差)を示します。
  6. $R preview Intro は、ユーザーが視聴できる、音声付きのリアルタイムウィンドウを開きます(スペースキーで 再生/一時停止、h/l で 1 秒移動、j/k で 1 フレーム移動、q で終了)。閉じるまで処理をブロックするため、 ユーザー向けに実行する場合はバックグラウンドで起動してください。上記の説明に沿ってコマンドを示し、 起動するかどうかを尋ねてください。編集後は、変更箇所に近い特定の秒数を指定してください。

エンコードしたサンプルが必要な場合は、$R render Intro --draft で 1 つのシーンを半分の解像度で エンコードします。$R render は、指定した最終書き出し用のフル動画を書き出します。

完成した動画を見せる前に、$R inspect --pops を実行してください。すべてのフレームを小さくレンダリングし、 静止フレーム間で 1 フレームのうちに画面の一部が変化するポップを警告します。たとえば、要素が現れる、 消える、または移動せずに別の要素の手前へ飛び出すといった変化です。各警告には、確認用の frame ... --crop ... コマンドが示されます。同じ領域で繰り返されるもの(カウンター、点滅するライト)は、 1 つの警告にまとめられます。

ルール:

  • 問題ないと言う前に、PNG を確認してください。
  • 多数の frame 呼び出しよりも strip を優先してください。構図だけを確認する場合は --scale 0.5 を追加してください。
  • 出力を解析する場合は --json を追加してください。結果は stdout に、進捗は stderr に出力されます。
  • --release を付けたままにしてください。デバッグビルドではレンダリングが何倍も遅くなります。
時刻の指定

120(フレーム)、3.2s、500ms、1:05.5、50%、start、end。構造体名でシーンを指定する場合は Intro(IntroScene にも一致し、大文字と小文字は区別されません)、#3(シーンのインデックス)、 Intro[1](その型の 2 番目のシーン)。シーン内では [email protected]、Intro@12、Intro@50%、Intro@end。 範囲:a..b(終端は含みません)、a..、..b、all、またはシーン全体を表すシーン名。 複数の時刻はカンマで区切ります。

すべてのコマンド
commanduse it to
timelineシーン、長さ、音声トラックとそのミックス設定を確認します
inspect [RANGE] [--every 0.1s | --all-frames] [--fail-on warning] [--pops]ピクセルをレンダリングせずに問題を見つけます。--pops は、表示されたり消えたりする要素も検出します
strip [RANGE | TIMES] -n N [--columns 4] [--width 480] [--crop x,y,w,h]1枚の画像で流れや動きを確認します
frame TIMES [-o dir] [--svg] [--crop x,y,w,h] [--zoom N] [--ids]選択したフレームのフルサイズ PNG(およびレイアウト済み SVG)、鮮明な切り抜き、ラベル付き要素を取得します
onion RANGE -n N動きの軌跡とイージングを確認します
svg TIME最終フレームの SVG をテキストとして確認します(位置、テキスト、色)
preview [TIME] [--paused] [--mute]ユーザー向けの、音声付きリアルタイムウィンドウを表示します
render [RANGE] [-o out.mp4] [--draft]動画またはその一部をエンコードします(音声も合わせて切り取られます)
audio analyze [RANGE] [--waveform w.png]シーンごとのラウドネス(LUFS)、トゥルーピーク、クリッピング、無音を確認します
audio at TIMESある時点で再生される音、そのファイル内の位置、音量を確認します
audio render [RANGE] -o a.wavミックスを WAV ファイルとして出力します
ブラウザーエディター

fframes には、タイムラインとスクラブ機能を備えたウェブエディターもあり、動画を対話的に調整したい場合に便利です。動画を WebAssembly にコンパイルして実行するため、Node.js と wasm-pack が必要です。セットアップ手順は、fframes リポジトリの hello-world サンプルにある editor/ フォルダーを参照してください (https://github.com/dmtrKovalenko/fframes/tree/main/examples/hello-world)。 ユーザーが GUI エディターを求めた場合は、このエディターについて案内してください。動画の視聴には preview を使い、自分で確認するには CLI を使ってください。

4. 動画の作成

impl Video for MyVideo<'_> {
    const FPS: usize = 30; const WIDTH: usize = 1920; const HEIGHT: usize = 1080;
    fn duration(&self) -> Duration<'_> { Duration::Auto }            // sum of the scenes
    fn audio(&self) -> AudioMap<'_> { AudioMap::none() }              // see references/audio.md
    fn define_scenes(&self) -> Scenes<'_> { Scenes::from(vec![&self.intro as &dyn Scene, &self.main]) }
    fn render_frame<'a>(&'a self, frame: Frame, ctx: &FFramesContext<'a, '_>) -> Svgr<'a> {
        fframes::svgr!(<svg xmlns="http://www.w3.org/2000/svg" width={Self::WIDTH} height={Self::HEIGHT}>
            <rect width={Self::WIDTH} height={Self::HEIGHT} fill={BACKGROUND} />
            {ctx.render_scenes(&frame)}
        </svg>)
    }
}
  • アイデアごとにシーンを1つ作成し、それぞれの長さは2~6秒にします。シーン内では、frame.seconds() はシーン開始からの秒数を表します。
  • 値が固定された動きには、svgr! 属性内で frame.animate(fframes::timeline!(...)) を直接使うのを基本とします。svgr! はこれらのアニメーションをキャッシュ済みの静的データにします。Easing::Spring { mass: 1.0, stiffness: 180.0, damping: 20.0 } を含め、イージングはタイムライン内に直接定義します。名前付きのイージング定数は任意です。スプリングは終了時刻を指定せず、自然に落ち着くようにします。
  • 動的な値や、この最適化パターンに当てはまらない呼び出し(animate_loop を含む)では、タイムラインを self 上に一度だけ構築し、参照を渡してサンプリングします。構築後に開始時刻が変化する場合や、カスタム/サブフレームのクロックを使う場合は、キャッシュ済みの AnimationRuntime 値を使います。カメラパラメーターやシェーダーユニフォームにも、これらの API を使えます。スプリングやトゥイーンの補間を重複して実装しないでください。references/design.md と references/api.md を参照してください。
  • {} を含まないマークアップは、フレーム間でキャッシュされます。装飾はリテラルのままにし、アニメーションする値はラップする <g transform={..} opacity={..}> に指定します。
  • render_frame は複数のスレッドで全フレームに対して実行されます。パニック、ファイル読み込み、重い処理を行わないでください。データはコンストラクター内または OnceLock で準備します。メディアの検索結果は Option を返すため、expect の代わりに Svgr::empty() にフォールバックしてください。
  • すべてのフォントファイルを media/ に置き、フォントファミリー名と数値の font-weight を指定して参照します。
  • テキストの幅は推測せず、測定してください。段落には frame.text_width、frame.text_fit(.., TextOverflow::Ellipsis)、frame.text_break_lines を使います。inspect ではキャンバスからはみ出したテキストは検出されますが、テキストが自身のボックスからはみ出した場合は検出されません。そのため、frame の PNG でボックスを確認してください。
  • GPU シェーダー(SkSL または Shadertoy GLSL)は、fframes::Shader を通じて Skia バックエンドで実行されます。画像や同期済みの動画フレームを入力として使用できます(グリーンスクリーンのキーイング、カラーグレーディングなど)。references/api.md を参照してください。
  • 3D ショット(製品、デバイス、素材上のロゴ、シーン内を移動するカメラ)は、fframes::three_d(機能 3d)で作成します。これは three.js 風のシーングラフで、SVG の下と上に <image> として描画します。シーンは一度だけ構築し、フレームごとにポーズを設定します。references/3d.md を参照してください。

5. 見栄えを良くする

references/design.md の要約:

  • 1つのシーンにつきアイデアは1つにし、文字を大きく、幅の8〜10%の余白を取り、ニュートラルカラーに加えて2〜3色と、強調用のアクセントカラーを1色使います。
  • 要素は300〜600 msのスプリングまたはイーズアウトで表示し、退出はより速く、200〜300 msのイーズインにします。関連する項目は60〜120 msずつずらします。動きが落ち着いてから、視聴者が読めるよう1〜2 s確保し、すべてを一度に動かさないでください。
  • シーンをクロスフェードします(fn overlap(&self) -> Overlap { Overlap::Previous(0.4) }。オーバーラップはシーンのduration()に加算されます。references/api.mdを参照してください)。または、カットをまたいで要素を引き継ぎます。静止中も少し動きを加え、画面が固まって見えないようにします。
  • 1920x1080の場合:タイトルは96〜140 px、本文は44〜60 px、1行あたり最大約8語、カードあたり3行までにします。ポートレート1080x1920はスマートフォンで視聴されるため、同じピクセルサイズ以上にし、プラットフォームのUIが上下を覆うので、中央80%の範囲にコンテンツを配置します。
  • ストリップを使い、各シーンをreferences/design.mdのチェックリストで確認します。

6. サウンド

オーディオファイルはmedia/に配置します(コンパイル時に含まれます。include_media_dir!(.., "media", stereo)を使わない限りモノラルです)。または、実行時にMediaDirectoryでフォルダーを読み込み、次のように配置します。

AudioMap::from([
    AudioTrack::new("music.mp3", Second(0.)..Eof).gain_db(-18.).fade_in(1.).fade_out(2.).duck_under_voice(),
    AudioTrack::new("vo.wav", Second(0.6)..Eof).voice(),
    AudioTrack::new("whoosh.wav", Second(3.1)..Eof).gain_db(-8.),
])

アニメーションを制御する定数と同じ定数を使って効果音のタイミングを設定します。$R audio analyze --waveform w.pngで音量を確認します(Web動画では統合ラウドネス約-14 LUFS、トゥルーピークは-1 dBTP未満、意図しない無音がないこと)。イベントで再生される音は$R audio at 3.1sで確認します。その後、$R previewでユーザーに試聴してもらいます。

7. 仕上げ

  1. $R inspect --fail-on warningが成功するか、残っている警告が意図した表示アニメーションであることを確認します。
  2. すべてのシーンのストリップが適切で、重要なフレームをフルサイズで確認していること。
  3. このファイルの先頭にある「No slop」リストに該当するものが、どのストリップにも残っていないこと。
  4. $R audio analyzeで適切な音量が示されること。
  5. レビュー待ちのGPU作業については、プレビューコマンドを示し、該当する秒数での実行を提案します。ユーザーが最終エクスポートを依頼したら、$R render -o out.mp4を実行し、次のコマンドでサイズ、フレーム数、オーディオを確認します。 ffprobe -v error -show_entries stream=codec_type,width,height,nb_frames,duration out.mp4

プレビューのレビューでは、具体的なプレビューコマンドと開始時刻を示し、起動することを提案します。最終エクスポート後は、出力パスと再生時間を伝えます。

トラブルシューティング

  • ffmpeg-sys-fframesでビルドが失敗する:手順1のシステムライブラリ(nasm、pkg-config、コーデックの-devパッケージ)が不足しています。
  • bindgenまたはlibclangのエラーによりSkiaバインディング(skia-bindings)のビルドが失敗する(Skiaは、事前ビルド済みのものが一致しない場合に限りソースからコンパイルされます。例:metalとvulkanを同時に使用する場合):LIBCLANG_PATHを動作するlibclangの場所に設定します(macOSのXcodeの場合: export LIBCLANG_PATH=$(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib)。
  • macOS 27 / Xcode 27でSkiaバインディングのコンパイルに失敗し、std___hash_table___node_allocatorでcannot find type `_Traits` が発生する:Skiaをソースからコンパイルした場合にのみ発生します(事前ビルド済みバイナリにはバインディングが含まれています)。skia-bindings 0.153.3にはbindgenルールがありません(rust-skia #1335)。事前ビルド済みバイナリが一致するようGPUバックエンドを1つだけ使うか、skia-bindings-0.153.3のコピーをパッチします(build_support/skia_bindgen.rsのOPAQUE_TYPESで、"std::__tree.*",の後に"std::__hash_table.*",を追加します)。その際は[patch.crates-io]を使います。
  • ファイルが存在するのに、macOS 27でcan't find crate for `fframes_media_dir_macro` が発生する:proc macroは古いRustでリンクされており、その出力をmacOS 27のローダーが拒否しています(「LINKEDIT string pool」エラー)。Rustを更新(rustup update。1.98では動作します)して、再ビルドします。
  • テキストが誤ったフォントで描画される、またはまったく描画されない:inspectに「No match for ... font-family」と表示されます。フォントファイルをmedia/に追加し、正確なファミリー名を使います。

コメント