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 단계 (정적) 또는 ImageResponse로 /api/og 추가 |
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를 추가하고, 그렇지 않으면 메타데이터에twitter: { card: "summary_large_image" }를 설정하면 Next.js가 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를 사용하여 빌드 시점에 페이지당 PNG를 렌더링합니다 (npm i satori @resvg/resvg-js). 레이아웃에서 다음과 같이 참조합니다:
<meta property="og:image" content={new URL(`/og/${slug}.png`, Astro.site)} />
astro.config.mjs에서 Astro.site를 설정해야 합니다. 폰트 파일: src/assets/fonts/에 TTF를 넣으세요.
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="Page title" />
<meta property="og:description" content="한 문장, ≤ ~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가 절대 경로인지, 접근 가능한지, 이미지 content-type인지, 약 1.91:1 비율이며 최소 600px 너비이고 5 MB 미만인지 확인합니다. 오류가 있으면 종료 코드 1을 반환합니다. ERROR로 표시된 모든 항목을 수정하고, WARN 항목은 권장 사항입니다.
참고: 소셜 플랫폼은 미리보기를 캐시합니다. 수정 후에는 플랫폼 자체 디버거 (LinkedIn Post Inspector, Facebook Sharing Debugger)를 사용하여 다시 스크랩하세요. X는 더 이상 공개 검증 도구가 없으므로 초안/DM에 게시하여 확인하세요. localhost URL은 해당 도구로 스크랩할 수 없으므로 먼저 배포하세요.
이미지 디자인 규칙
- 1200×630, PNG, ~60 px 안전 여백 내에 텍스트; 제목 ≤ ~60자, 최대 3줄.
- 높은 대비; 피드에서는 작게 (~500 px 너비) 표시됩니다. 50% 확대/축소로 테스트하세요.
- 브랜드 이름/로고 포함; 작은 텍스트 (< 1200 너비에서 28 px)는 피하세요.
- 플랫폼별 참고 사항은
references/platform-specs.md를 참조하세요.
완료 조건
- 모든 색인 가능한 페이지가 og:title, og:description, og:image (절대 경로), twitter:card를 반환합니다.
-
check_og.py가 홈 페이지와 각 라우트 유형의 페이지 하나 이상에 대해 종료 코드 0을 반환합니다. - 이미지가 올바르게 보입니다 (PNG 하나를 열어서 확인).