mcpField
L
loop-cover

loop-cover

github.com/charlie947クリエイティブ・メディア4561.6k 回インストール2 週間前に更新
リポジトリ

loop-cover について

静止画のカバーに動きを一つ加え、ループGIFにするクリエイティブスキルです。HTMLと画像それぞれの手順に加え、ループやファイルの確認方法を説明します。

主な機能

  1. 01指定した一要素をアニメーション化
  2. 02HTMLと画像のカバーに対応
  3. 03継ぎ目のない9秒ループを作成
  4. 04動きとループ境界を測定
  5. 05ディザなしでGIFをエンコード

活用シーン

  1. 01フィード用カバーに控えめな動きを追加
  2. 02静止画の一要素だけを動かす
  3. 03公開前にGIFのループを確認

インストール

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

$npx skills add https://github.com/charlie947/motion-graphics-skills --skill loop-cover

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

詳細

ループするカバーGIF

動きのあるカバーは、静止画ばかりのフィードで目を引きます。ただし、動きが小さく、ループが途切れず、最初のフレームだけでも意味が伝わる場合に限ります。

始める前に: brand.md と MOTION.md があれば読んでください。なければ、まず brand-intake を実行するか、カラーコード、フォント、ロゴファイルを尋ねてください。これらが揃うまでは、結果がブランドに沿っていると判断しないでください。

ステップ 1:3 つのことを尋ねて、返事を待つ

  1. カバー。 完成した静止画(PNG)、または HTML で作成したカバー。896 x 640、または同じ 7:5 の比率のより大きな画像。
  2. 動かす要素を 1 つ、 はっきりと指定してもらいます。「灯台の光線」「オレンジ色の線が描かれていく」「細胞間の線」などです。
  3. 動き方。 脈動、描画、ゆっくりした漂い、または発光です。動きは 1 つだけにし、3 つにしないでください。

ステップ 2:作成する

カバーが HTML の場合: 指定された要素だけを時間の純粋関数としてアニメーション化し、window.seek(seconds) を追加して、20fps で 180 フレーム(9 秒)をキャプチャします。

カバーが画像の場合: 静止画をコードでアニメーション化します。指定された要素を色でマスクし(たとえば、青が赤より大幅に強いすべてのピクセル)、端を数ピクセルぼかして、フレームごとにそのピクセルだけを変化させます。マスクの外側は一切動かしません。

どちらの場合も、9 秒間にわたる滑らかなサイン波 1 周期、または描画、静止、フェードを 1 回だけ使い、最後のフレームから最初のフレームへ自然につながるようにします。

フレーム 1 が完成した画像になるようにループを回転させます。 受信トレイやリンクのプレビューでは、フレーム 1 が静止画として表示されます。フレーム i では ((i + offset) mod 180) / 20 秒の時点を描画します。offset は、描画が完了した状態が最初に来るように設定します。

フラットな画像ではディザリングが各フレームにちらつきを加えるため、ディザリングなしでエンコードします。

ffmpeg -y -framerate 20 -i f%03d.png -filter_complex "split[x][y];[x]palettegen=max_colors=128:stats_mode=full[p];[y][p]paletteuse=dither=none" -loop 0 cover.gif

ステップ 3:測定する

ffmpeg -v error -y -i cover.gif -vf scale=216:154,format=gray -f rawvideo frames.raw
python3 -c "
n = 216 * 154
d = open('frames.raw', 'rb').read()
f = [d[i:i + n] for i in range(0, len(d), n)]
diff = lambda a, b: sum(abs(x - y) for x, y in zip(a, b)) / n
print('frames', len(f))
print('seam', round(diff(f[-1], f[0]), 2))
print('excursion', round(max(diff(x, f[0]) for x in f), 2))
"

これまでに公開したカバーの目安は、180 フレーム、継ぎ目の値が 0.0〜0.3、動きの振幅が約 0.7〜2.8、ファイルサイズが 0.6〜2.3 MB です。振幅がほぼゼロなら、目に見える動きはありません。

苦労して学んだこと

  • 「画像全体を変えてしまいました。」 最初に作った GIF では、帯がフレーム全体を横切っていました。指定されたものだけをアニメーション化してください。
  • 動画モデルはカメラの動きを加えます。 「カメラは完全に固定」と指示しても、ズームインしてきました。カメラを固定するには、静止画をコードでアニメーション化するしかありません。
  • 中間フレームで動きを測定しないでください。 サイン波はそこでゼロに戻るため、動作するアニメーションでも動きがないと報告されます。フレーム 0 に対する最大の変化を測定してください。
  • ffmpeg の eq フィルターでは eval=frame を追加してください。 そうしないと式は一度しか実行されず、何も動きません。
  • 幅を 240px に縮小して、もう一度確認してください。 受信トレイでの表示サイズです。動く要素が見えなくなるなら、小さすぎます。
  • GIF 自体をアップロードしてください。 アップロードツールによっては PNG に変換され、アニメーションが気付かないうちに消えてしまいます。アップロードしたリンクが .gif で終わっていることを確認してください。

コメント