Animated OG image(アニメーションOG画像)
このスキルが使用するすべてのファイルは、このSKILL.mdと同じフォルダ内に格納されています。パスはそのフォルダからの相対パスです。他のスキルや他のフォルダのものは一切必要ありませんので、探しに行かないでください。ユーザーが別の場所を指定しない限り、生成物はすべて現在のプロジェクトの out/og-image-animated/ に保存します。
静的な共有カードを、短く落ち着いたリビールアニメーションにします。
- 空のカード: 背景とソフトなグローのみ。
- ブランドマークとタイトルが上からドロップイン(フェード+スライドダウン)。
- アプリウインドウが下から上昇(フェード+スライドアップ)し、静的なカードとまったく同じ位置に落ち着きます。
- 最終フレームで停止。この最終フレームは静的な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) から | 900ms | 100ms |
| タイトル | opacity: 0; translateY(-48px) から | 1000ms | 250ms |
| アプリウインドウ | opacity: 0; translateY(320px) から | 1300ms | 700ms |
カードに合わせて距離を調整してください。アプリは下端より大部分が下(カードの高さの約半分)から開始し、タイトルはその静止位置の約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がサポートされている場合に使用してください。