Communitygithub.com

og-image-animated

プロジェクトのOG共有カードを数秒のWebアニメーションに変換します。ブランドマークとタイトルが上から、アプリが下から現れて、最終的なカードに落ち着きます。MP4、GIF、最終フレームのPNGを生成します。

og-image-animated とは?

このスキルは、プロジェクトの既存のOG画像(Open Graph共有カード)を、短いWebアニメーションに変換します。ブランドマークとタイトルが上からフェードイン&スライドダウンし、続いてアプリウインドウが下からフェードイン&スライドアップして静的なカードとまったく同じレイアウトで静止します。アニメーションは1つのコンポーネントに`animated`プロパティを追加する形で実装され、静的なPNGとアニメーションが常に一致するようになっています。アニメーションはCSSキーフレームと`opacity`+`transform: translateY`のみを使用し、滑らかで短い(約3〜4秒)ものになります。また、アニメーションを再生するWebルートを作成し、指定したスクリプトでフレームごとに録画してMP4、GIF、最終フレームのPNGを出力します。Playwrightとffmpegに依存し、開発サーバー上で動作します。結果のGIFは約3MB以下に抑えることが推奨されます。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/paralect/saas-skills/tree/HEAD/skills/og-image-animated

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Animated OG image(アニメーションOG画像)

このスキルが使用するすべてのファイルは、このSKILL.mdと同じフォルダ内に格納されています。パスはそのフォルダからの相対パスです。他のスキルや他のフォルダのものは一切必要ありませんので、探しに行かないでください。ユーザーが別の場所を指定しない限り、生成物はすべて現在のプロジェクトの out/og-image-animated/ に保存します。

静的な共有カードを、短く落ち着いたリビールアニメーションにします。

  1. 空のカード: 背景とソフトなグローのみ。
  2. ブランドマークとタイトルが上からドロップイン(フェード+スライドダウン)。
  3. アプリウインドウが下から上昇(フェード+スライドアップ)し、静的なカードとまったく同じ位置に落ち着きます。
  4. 最終フレームで停止。この最終フレームは静的なOG画像と一致していなければなりません。

参考例: references/pulse.gif(結果)と references/pulse-frames.png(4つのフレーム: 開始、タイトルイン、アプリ上昇中、最終)。

ルール

  • 静的なカードから始めること。 プロジェクトにOGカードコンポーネントがまだない場合は、まず references/static-card.md(実際の製品、現在のサイトからのメッセージ、現実的なデータ)に従って構築します。アニメーションは動きのみを追加します。同じマークアップ、同じ最終レイアウトで、新しいコンテンツはありません。
  • 1つのコンポーネント、2つのモード。 既存のカードコンポーネントをコピーするのではなく、animated プロパティを追加します。これにより、静的なPNGとアニメーションが乖離することがありません。プロパティがない場合は何もアニメーションしません。
  • 動きのみ、エフェクトなし。 opacity + transform: translateY のみ、1つの共有イーズアウトカーブ(cubic-bezier(0.16, 1, 0.3, 1))。バウンス、ブラー、スケールポップ、タイプライター文字、回転要素は禁止です。
  • 短く。 全体のタイムラインは約2〜2.5秒、その後約1.5秒の停止。タイトルは約1.3秒までに完全に読み取れる状態でなければなりません。
  • CSSアニメーションのみ(キーフレーム + animation と both フィル)、カード内部にJS駆動のトゥイーンやタイマーはなし。レコーダーはWebアニメーションAPIを介してCSSアニメーションをシークします。JS駆動の動きは決定論的にキャプチャされません。

タイムライン

要素キーフレーム持続時間遅延
ブランドマークopacity: 0; translateY(-48px) から900ms100ms
タイトルopacity: 0; translateY(-48px) から1000ms250ms
アプリウインドウopacity: 0; translateY(320px) から1300ms700ms

カードに合わせて距離を調整してください。アプリは下端より大部分が下(カードの高さの約半分)から開始し、タイトルはその静止位置の約1つ分の高さ上から開始するようにします。フローティングパネルがある場合は、ウインドウの開始より+200ms遅れて到着させてください。

手順

1. 発見

  • 静的なカードコンポーネントとそのレンダリングルート(例: og-image.tsx、/og/<page>)、および public/ 内の現在のPNGを見つけます。
  • ブランドマーク、タイトル、アプリウインドウのラッパーを確認します。ウインドウが zoom を使ってフィットしている場合は、内部のラッパーをアニメーションさせ、ズームされた要素はそのままにします。そうしないとオフセットが正しく保たれません。

2. アニメーションモードの追加

カードコンポーネント内:

const KEYFRAMES = `
@keyframes og-drop { from { opacity: 0; transform: translateY(-48px); } to { opacity: 1; transform: none; } }
@keyframes og-rise { from { opacity: 0; transform: translateY(320px); } to { opacity: 1; transform: none; } }
`;
const EASE = 'cubic-bezier(0.16, 1, 0.3, 1)';
const enter = (name: string, ms: number, delay: number) => ({ animation: `${name} ${ms}ms ${EASE} ${delay}ms both` });

// <div data-og-frame …>{animated && <style>{KEYFRAMES}</style>} …
// brand:  style={animated ? enter('og-drop', 900, 100) : undefined}
// title:  style={animated ? enter('og-drop', 1000, 250) : undefined}
// window: <div style={{ zoom }}><div className="h-full" style={animated ? enter('og-rise', 1300, 700) : undefined}>…

キーフレームはコンポーネント内(<style> タグ)またはプロジェクトのグローバルCSSに配置します。Tailwind v4では、@theme 内のキーフレームは対応する --animate-* トークンが使用された場合にのみ出力されるため、コンポーネント内かプレーンなCSSを使用することを推奨します。

3. 再生用Webルートの追加

静的なルートと同じ階層に、例: /og/<page>-animated(noindex、アプリのクロームなし):

  • <Card animated /> を1200×630のフレーム内にレンダリングします。
  • プレビュー用にリプレイ: 約4.5秒ごとにカードを key を変更して再マウントします。
  • ?loop=0 は1回だけ再生します(レコーダーがこれを使用します)。検索パラメータは最初に文字列に正規化します。TanStackなどのルーターは ?loop=0 を数値 0 として解析し、チェックを忘れると録画中にカードが再マウントされ続けます。

ブラウザで開いて数回動作を確認してください。エントランスの順序、アニメーション開始前のフラッシュ、静止状態が静的なカードと一致していることを確認します。

4. MP4 + GIF の録画

開発サーバーを起動した状態で:

node <このスキルのフォルダ>/scripts/record.mjs \
  --url "http://localhost:<port>/og/<page>-animated?loop=0" \
  --out out/og-image-animated/og-<page>

og-<page>.mp4(2400×1260、H.264、30fps)、og-<page>.gif(幅1200px、パレット最適化、ループ)、og-<page>.png(最終フレーム)を書き出します。仕組み: ページ上のすべてのアニメーションを一時停止し、タイムラインの長さを読み取り、すべてのアニメーションをフレームごとにシークし、[data-og-frame] の固定クリップをスクリーンショットします。毎回同じ結果が得られ、フレーム落ちはありません。オプション: --fps、--hold、--lead、--scale、--formats mp4,gif,png、--selector。

ffmpeg がPATHに必要です。Playwrightは初回実行時にこのスキルの scripts/ フォルダにインストールされ、Chromiumも見つからない場合にインストールされます。

注意点:

  • ページは動きの抑制(reduced motion)を強制してはいけません。多くのグローバルスタイルシートは prefers-reduced-motion の下でアニメーションを短縮します。レコーダーはこれをエミュレートせず、アニメーションが見つからないとエラーを出力します。
  • 要素のスクリーンショットは「安定性」を待ちますが、アニメーション中は安定しません。そのため、スクリプトはページ領域をクリップします。
  • ポートが本当にこのアプリを提供していることを確認してください(別のローカルサーバーが localhost で応答する可能性があります)。

5. レビュー

コンタクトシートを抽出して確認します:

ffmpeg -y -loglevel error -i og-<page>.mp4 \
  -vf "select='eq(n\,8)+eq(n\,22)+eq(n\,40)+eq(n\,<last>)',scale=1000:-1,tile=2x2" -frames:v 1 sheet.png
  • フレーム ~0.25秒: 空のカード(グローのみ)、レイアウトのポップなし。
  • ~0.7秒: タイトルが表示またはほぼ表示、アプリはまだ見えていない。
  • ~1.3秒: アプリが上昇中、タイトルは完全に読める。
  • 最終フレーム: 静的なPNGと内容が同一。

GIFは適度に小さく(約3MB以下)保つようにしてください。大きい場合は --fps(20〜24)を下げるか、--hold を短くします。

出力

ユーザーに伝えること:

  • プレビュールートのURL(ループ)と書き出されたファイル(MP4、GIF、PNG)
  • 再生成コマンド
  • タイムライン(何が動くか、持続時間)
  • og:image は静的なPNGのままにしなければならないこと。ソーシャルプラットフォームはアニメーションOG画像を再生しません。MP4/GIFは投稿、README、ランチングページ、または og:video がサポートされている場合に使用してください。

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

関連スキル