#!/usr/bin/env node /** * Raster 1200×630 Open Graph images from the marketing hero, a templates * lockup, and each catalog article's section banner. * * Run: npm run generate:og-images */ import path from "node:path"; import { fileURLToPath } from "node:url"; import sharp from "sharp"; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const PUBLIC = path.join(ROOT, "public"); const OG_WIDTH = 1200; const OG_HEIGHT = 630; const CATALOG_SLUGS = [ "resolving-active-conflicts", "operational-security-mutual-aid", "making-decisions-without-hierarchy", "integrating-new-members-without-dilution", "avoiding-burnout-sustainability-in-the-ruins", "how-chaos-concentrates-control", "digital-mediation-and-the-death-of-nuance", "knowledge-management-and-institutional-amnesia", ]; const TEMPLATES_LOCKUP = ` `; async function coverPng(input, output, options = {}) { await sharp(input, options) .resize(OG_WIDTH, OG_HEIGHT, { fit: "cover", position: "centre" }) .png() .toFile(output); } async function main() { const defaultOut = path.join(PUBLIC, "assets/marketing/og-image.png"); const templatesOut = path.join(PUBLIC, "assets/marketing/og-image-templates.png"); await coverPng( path.join(PUBLIC, "assets/marketing/hero-image.png"), defaultOut, ); console.log("Wrote", path.relative(ROOT, defaultOut)); await sharp(Buffer.from(TEMPLATES_LOCKUP)) .png() .toFile(templatesOut); console.log("Wrote", path.relative(ROOT, templatesOut)); for (const slug of CATALOG_SLUGS) { const svgPath = path.join(PUBLIC, "content/blog", `${slug}-section.svg`); const outPath = path.join(PUBLIC, "content/blog", `${slug}-og.png`); await coverPng(svgPath, outPath, { density: 300 }); console.log("Wrote", path.relative(ROOT, outPath)); } } main().catch((error) => { console.error(error); process.exit(1); });