og-image-kit は何をしますか?
目標: すべての公開ページに 1200×630 の共有画像と正しい og:* / twitter:* タグが設定され、scripts/check_og.py を使って検証されていること。単に書き込んだだけでは不十分です。
ステップ 1 — スタックを判別する
コードを書く前にリポジトリを確認してください:
| シグナル | スタック | 移動先 |
|---|---|---|
package.json に next があり、app/(または src/app/)ディレクトリがある | Next.js App Router | ステップ 2A |
next があるが pages/ のみ | Next.js Pages Router | ステップ 2C(静的)または /api/og を ImageResponse で追加 |
package.json に astro がある | Astro | ステップ 2B |
| プレーンHTML、Hugo、Jekyll、Vite SPA、その他 | 静的 | ステップ 2C |
また、サイトの正規ベースURL(環境変数 NEXT_PUBLIC_SITE_URL、astro.config.* の site)、ブランドカラー、ロゴ、使用フォントも見つけてください。見つからない場合のみユーザーに質問してください。
ステップ 2A — Next.js App Router
- ルートレイアウトが
metadataBaseをエクスポートしていることを確認します(OG URLは絶対パスである必要があります):export const metadata = { metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000") } assets/nextjs/opengraph-image.tsxをapp/opengraph-image.tsxにコピーします(サイトデフォルト)。BRAND、色、タグラインを編集します。- 動的ルート(ブログ記事、商品など)の場合、ルートセグメントにコピーします(例:
app/blog/[slug]/opengraph-image.tsx)。assets/nextjs/dynamic-opengraph-image.tsxを使用します。これはparamsを読み取り、データソースからタイトルを読み込みます。 Next.js 15+ ではparamsは Promise です —awaitしてください。 - Xカードを変更する必要がある場合のみ
twitter-image.tsxも追加します。それ以外の場合、Next.js はメタデータでtwitter: { card: "summary_large_image" }を設定すればOG画像を再利用します。 - ページごとのテキスト: 各ページの
metadata/generateMetadataでtitleとdescriptionを設定します。 - カスタムフォント:
fetch(new URL("./Inter-Bold.ttf", import.meta.url))またはreadFileでTTF/OTF(WOFF2不可)を読み込みます。CJKテキストにはCJKフォントファイルが必要です。そうしないと文字が表示されません — サイズを抑えるためにサブセット化してください。
守るべき制限(next/og / satori): flexboxのみ(grid不可)。複数の子を持つ div にはすべて display: "flex" が必要です。バンドルサイズを小さく保ってください — Next.js の ImageResponse ドキュメントでは、JSX + CSS + フォント + 画像で500 KBの制限が記載されています。大きなフォントはレンダリングを遅くするので、サブセット化してください。
ステップ 2B — Astro
assets/astro/og-endpoint.ts を src/pages/og/[...slug].png.ts として使用します。ビルド時に satori + @resvg/resvg-js(npm i satori @resvg/resvg-js)でページごとにPNGをレンダリングし、レイアウトから参照します:
<meta property="og:image" content={new URL(`/og/${slug}.png`, Astro.site)} />
Astro.site は astro.config.mjs で設定する必要があります。フォントファイル: TTFを src/assets/fonts/ に配置します。
ステップ 2C — 静的サイト / その他
PNGを一度生成してコミットします:
python3 scripts/generate_og.py --pages pages.json --out public/og --brand "Acme" --bg "#0f172a" --fg "#ffffff" --accent "#38bdf8"
pages.json は {"slug": "pricing", "title": "...", "subtitle": "..."} のリストです(assets/pages.example.json 参照)。Pillowが必要です(pip install pillow)。ブランドフォントやCJKテキスト(例: Noto Sans SC)には --font path/to/font.ttf を渡します。その後、各ページにタグを追加します(テンプレートは references/meta-tags.md)。
ステップ 3 — 必須タグ(すべてのページ)
<meta property="og:title" content="ページタイトル" />
<meta property="og:description" content="1文、約160文字以内" />
<meta property="og:image" content="https://example.com/og/page.png" /> <!-- 絶対URL -->
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://example.com/page" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
Next.js は metadata + opengraph-image.tsx からこれらを生成します。重複して手動で記述しないでください。
ステップ 4 — 検証(省略しないこと)
実行中のサイト(開発サーバー、プレビューデプロイ、または本番)に対して実行:
python3 scripts/check_og.py http://localhost:3000/ http://localhost:3000/pricing
python3 scripts/check_og.py --json https://example.com/ # 機械可読
各ページを取得し、必須タグの存在、og:image が絶対URLでアクセス可能で画像コンテンツタイプであること、縦横比が約1.91:1、幅が600px以上、サイズが5MB未満であることをチェックします。エラーがあると終了コード1。ERROR とマークされたものはすべて修正してください。WARN は推奨事項です。
注意: ソーシャルプラットフォームはプレビューをキャッシュします。修正後、各プラットフォームのデバッガ(LinkedIn Post Inspector、Facebook Sharing Debugger)を使用して再スクレイピングしてください。Xには現在公開バリデータはありません。下書き/DMに投稿して確認します。localhost URLはそれらのツールでスクレイピングできません — 先にデプロイしてください。
画像のデザインルール
- 1200×630、PNG、テキストは約60pxの安全マージン内。タイトルは約60文字以内、最大3行。
- 高いコントラスト。フィードでは小さく表示される(約500px幅)。50%ズームでテストしてください。
- ブランド名/ロゴを含める。小さなテキスト(1200幅で28px未満)は避けてください。
- プラットフォームごとの注意点は
references/platform-specs.mdを参照してください。
完了条件
- インデックス可能なすべてのページが og:title、og:description、og:image(絶対URL)、twitter:card を返す
-
check_og.pyがホームページと各ルートタイプの少なくとも1ページで終了コード0を返す - 画像が正しく見える(PNGを1つ開いて確認する)