エディトリアルOGカード
投稿ごとに一貫したリンクプレビュー画像。各カードは以下で構成されます:
- キッカー(シリーズまたはセクション)、トピック、メタ行(読了時間または日付)を表示するトップルール
- 大きなセリフ体の見出し。実際のテキストとして設定されるためスペルミスがなく、必要に応じてのみ縮小され、アクセントカラーで表示される1~2語を含む
- イニシャルまたは写真、および投稿のURLを含むバイライン
- 右側のアート:投稿のスラッグから選択される4つのブロック構成、ユーザーが選んだ画像、または何もなし。見出しはより広く表示される
スクリプトが投稿を読み取ってcards.jsonを作成し、確認後に2番目のスクリプトがマシン上のChromeを使用して各カードをレンダリングします。追加インストールは不要です。
必要なもの
- Node.js 18以降。
- Chrome、Chromium、またはEdge。スクリプトは通常の場所から自動検出します。見つからない場合は
CHROME_PATHを設定してください。 - レンダリング中はGoogle Fontsスタイルシート(Instrument Serif、Inter、IBM Plex Mono)にアクセスするためインターネット接続が必要です。オフラインレンダリングについてはトラブルシューティングを参照してください。
このスキルのフォルダは<skill>です。このSKILL.mdがあるフォルダを指します。
手順
1. cards.jsonを作成する
Markdown投稿から(Astro、Hugo、Jekyll、Eleventy、Next.js MDXなど、フロントマターを持つ任意のもの):
node <skill>/scripts/from-posts.mjs content/blog --site=yourblog.example --path=/blog/ --out-dir=public/og
指定したフォルダ以下のすべての.md、.mdx、.markdownファイルを読み取り、新しい順に各投稿のカードを1枚作成します。draft: trueの投稿はスキップされます。フロントマターから以下のフィールドを取得します:
| カードフィールド | 取得元 |
|---|---|
slug | slug、なければpermalink、なければファイル名(index.mdの場合はフォルダ名)、先頭の日付は除去 |
title | og_title、なければtitle |
kicker | kicker、なければseries、なければ--kicker=...、なければ"Article" |
topic | topic、なければ最初のcategory、なければ最初のタグ |
meta | reading_time、なければ230語/分で計算した文字数:「8 min read」 |
author | author(テキスト、またはその下のname)、なければ--author=... |
url | --site + --path + slug、著者の下に表示 |
out | <out-dir>/<slug>.png;--out-dirなしの場合、投稿の隣に<name>.og.png(index.mdの場合はog.png) |
投稿が追加されたら再実行してください。cards.json内の既存カードは編集内容を保持し、新しい投稿は追加され、削除された投稿は取り除かれます。
手動で、Markdownではないページ(ニュースレター、ランディングページ、ドキュメントセクションなど)の場合は、同じ構造を自分で記述します:
{
"theme": { "paper": "#131313", "ink": "#f2ede4", "accent": "#ff7a45" },
"defaults": { "kicker": "Night Desk", "author": "Ines Varga" },
"cards": [
{
"slug": "issue-41",
"title": "Why every newsroom is quietly *rebuilding its CMS*",
"topic": "Issue 41",
"meta": "Oct 2026",
"url": "nightdesk.example/41",
"tags": ["#media", "№ 41"]
}
]
}
defaultsは、カードで省略されたフィールドを補完します。
2. カードを編集する
cards.jsonを開き、タイトルを確認します:
- 要点を伝える1~2語を
*アスタリスク*で囲みます。これらはアクセントカラーのイタリックで表示されます。"Shipping a design system *in a week*"。 - 見出しは70文字以内が最適で、上限は110文字です。約80文字を超えるとフォントサイズが小さくなります。投稿のフロントマターで
og_titleを使用するか、cards.jsonで直接短くしてください。
カードが持つことのできるすべてのフィールド:
| フィールド | 説明 | 制限 |
|---|---|---|
title | 見出し(必須) | 110 |
slug | ファイル名を決定し、レイアウトを選択(必須、outが設定されている場合は不要) | – |
out | PNGの出力先。cards.jsonからの相対パス(デフォルトog/<slug>.png) | – |
kicker | 左上のラベル。アクセントカラーで表示 | 24 |
topic | キッカーの後に続くトピック。アートのデフォルトハッシュタグとしても使用 | 28 |
meta | 右上:読了時間、日付、号 | 20 |
author | バイライン名。イニシャルは円内に表示 | 32 |
avatar | イニシャルの代わりに使用する写真(パスまたはURL) | – |
url | 名前の下に表示 | 48 |
art | blocks(デフォルト)、image、noneのいずれか | – |
image | "art": "image"の場合の画像(パスまたはURL)。390×430にトリミング | – |
layout | 1~4。ブロック構成を自分で選択 | – |
tags | アートに表示する最大2つの小さなラベル。例:["#css", "Part 2"] | 各16 |
テーマは全カードの外観を設定します:paper(背景)、ink(テキスト)、accent(アクセント)を16進数で指定し、さらにserif、sans、monoで他のGoogle Fontsファミリーを指定できます。アクセントカラーはブロックにそのまま使用され、テキストには読みやすさを確保するために暗くまたは明るく調整されます。2つのテーマ例:デフォルトのインクブルー(#fafaf7、#17181c、#2433e8)とナイト(#131313、#f2ede4、#ff7a45)。
3. レンダリング
node <skill>/scripts/render.mjs cards.json
まずすべてのカードをチェックし、すべての問題を一度にリストアップします。その後、4枚ずつカードをレンダリングし(1枚あたり約1秒)、すべてのPNGが1200×630であることを確認します。--scale=2を追加すると2400×1260の画像(高DPI画面でより鮮明、ファイルサイズは約2倍)が生成され、--only=slug,slugで一部のカードのみ再レンダリングできます。
4. 確認
cards.jsonの隣に作成されるog-preview.htmlを開きます。すべてのカードが並んで表示されます。大幅に縮小された見出し(短くする必要があります)、アクセントワードが誤ったフレーズに適用されていないか、隣接するカードが十分に異なっているかを確認します。カードのlayoutを変更して別の構成を選択します。
5. サイトに組み込む
各ページが絶対URLで画像を指すようにして初めて、カードはプレビューに表示されます。ページの<head>に以下を追加します:
<meta
property="og:image"
content="https://yourblog.example/og/design-system-in-a-week.png"
/>
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Shipping a design system in a week" />
<meta name="twitter:card" content="summary_large_image" />
投稿ごとではなく、スラッグから構築して、投稿レイアウトまたはテンプレートで一度だけ実装します:
- Next.js(App Router):投稿ルートの
generateMetadataで、openGraph: { images: [{ url:/og/${slug}.png, width: 1200, height: 630 }] }とtwitter: { card: 'summary_large_image' }を返します。ルートレイアウトでmetadataBaseを設定し、URLが絶対パスになるようにします。 - Astro、Eleventy、Jekyll、Hugo:ベースレイアウトのheadに、サイトURL +
/og/+ ページのスラッグを使用してタグを追加します。 - 投稿の隣に画像を配置する場合(
--out-dirなし):フレームワークが同じ場所にあるファイルを提供するパスを使用します。
デプロイ後、投稿URLをリンクプレビューチェッカーに貼り付けるか、X、LinkedIn、Slackの下書きでカードを確認します。プラットフォームはプレビューをキャッシュするため、画像を変更してから表示されるまで時間がかかることがあります。
6. 継続運用(オプション)
新しい投稿ごとにカードを自動生成するには、このスキルのscripts/フォルダとtemplate/フォルダをリポジトリにコピーし(例:tools/og/)、ビルド前に両方のスクリプトを実行します。例えばpackage.jsonのprebuildスクリプトとして:
"prebuild": "node tools/og/scripts/from-posts.mjs content/blog --site=yourblog.example --path=/blog/ --out-dir=public/og && node tools/og/scripts/render.mjs cards.json"
ビルドマシンにChromeが必要です。ほとんどのCIイメージには含まれていますが、ない場合はCHROME_PATHを設定してください。
トラブルシューティング
render: fix cards.json first:各行にカード名、フィールド、制限が表示されます。- Chromeが見つからない:ChromeまたはChromiumをインストールするか、
CHROME_PATHを実行可能ファイルへのパスに設定します。 - 見出しが標準的なセリフ体で表示される、またはラベルがシステムフォントになる:Google Fontsスタイルシートが読み込まれていません。オフラインレンダリングを行うには、Instrument Serif、Inter、IBM Plex Mono(すべてGoogle Fontsから無料で入手可能)をインストールし、テーマで
"fonts": ""を設定します。"fonts"には、他のフォントファミリー用の独自のスタイルシートURLを指定することもできます。 - プラットフォームのプレビューに古い画像が表示される、または何も表示されない:
og:imageURLがブラウザで開くこと、そして絶対URL(https://とドメインを含む)であることを確認し、その後プラットフォームにページの再クロールを依頼するか、キャッシュの期限が切れるのを待ちます。
ファイル
scripts/from-posts.mjs:フロントマターをcards.jsonに変換。後続の実行では編集内容を保持。依存関係なし。scripts/render.mjs:cards.jsonをチェックし、PNGをレンダリングし、og-preview.htmlを書き出します。依存関係なし。scripts/chrome.mjs:Chromeを検出し、スクリーンショットを撮影します。template/:カード本体。card.htmlとcard.cssがレイアウト、card.jsがテキストの入力、読みやすい色の選択、アートの描画、見出しのフィッティングを行います。examples/field-notes/:小さなブログ(posts/)と、from-posts.mjsから作成されたcards.json、アクセントワードが追加されています。examples/night-desk/:ダークテーマのニュースレター用に手書きされたcards.json。Lookbkのプレビューはこれらからレンダリングされています。NOTICE.md:このスキルが使用するフォントとソフトウェアの情報。